edb-1.31/0000755000175000017500000000000011016452347010367 5ustar ttnttnedb-1.31/configure0000755000175000017500000025233011016452253012277 0ustar ttnttn#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.62 for EDB 1.31. # # Report bugs to . # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH if test "x$CONFIG_SHELL" = x; then if (eval ":") 2>/dev/null; then as_have_required=yes else as_have_required=no fi if test $as_have_required = yes && (eval ": (as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=\$LINENO as_lineno_2=\$LINENO test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } ") 2> /dev/null; then : else as_candidate_shells= as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. case $as_dir in /*) for as_base in sh bash ksh sh5; do as_candidate_shells="$as_candidate_shells $as_dir/$as_base" done;; esac done IFS=$as_save_IFS for as_shell in $as_candidate_shells $SHELL; do # Try only shells that exist, to save several forks. if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { ("$as_shell") 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : _ASEOF }; then CONFIG_SHELL=$as_shell as_have_required=yes if { "$as_shell" 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : (as_func_return () { (exit $1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = "$1" ); then : else exitcode=1 echo positional parameters were not saved. fi test $exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } _ASEOF }; then break fi fi done if test "x$CONFIG_SHELL" != x; then for as_var in BASH_ENV ENV do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test $as_have_required = no; then echo This script requires a shell more modern than all the echo shells that I found on your system. Please install a echo modern shell, or manually run the script under such a echo shell if you do have one. { (exit 1); exit 1; } fi fi fi (eval "as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0") || { echo No shell found that supports shell functions. echo Please tell bug-autoconf@gnu.org about your system, echo including any error possibly output before this message. echo This can help us improve future autoconf versions. echo Configuration will now proceed without shell functions. } as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='EDB' PACKAGE_TARNAME='edb' PACKAGE_VERSION='1.31' PACKAGE_STRING='EDB 1.31' PACKAGE_BUGREPORT='ttn@gnuvola.org' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datarootdir datadir sysconfdir sharedstatedir localstatedir includedir oldincludedir docdir infodir htmldir dvidir pdfdir psdir libdir localedir mandir DEFS ECHO_C ECHO_N ECHO_T LIBS build_alias host_alias target_alias INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA EMACS sitelisp badnamesp LIBOBJS LTLIBOBJS' ac_subst_files='' ac_user_opts=' enable_option_checking with_sitelisp enable_badnames ' ac_precious_vars='build_alias host_alias target_alias' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { $as_echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { $as_echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) { $as_echo "$as_me: error: Unrecognized options: $ac_unrecognized_opts" >&2 { (exit 1); exit 1; }; } ;; *) $as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; } done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || { $as_echo "$as_me: error: Working directory cannot be determined" >&2 { (exit 1); exit 1; }; } test "X$ac_ls_di" = "X$ac_pwd_ls_di" || { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 { (exit 1); exit 1; }; } # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 { (exit 1); exit 1; }; } pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures EDB 1.31 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/edb] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of EDB 1.31:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-badnames Do not support backward-compatible but namespace-polluting aliases (see README) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-sitelisp=DIR Override the default site-lisp directory Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF EDB configure 1.31 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by EDB $as_me 1.31, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test -r "$ac_site_file"; then { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 $as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 $as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} { (exit 1); exit 1; }; } fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # allow env override but do not get fooled by EMACS=t test t = "$EMACS" && unset EMACS # the next line does nothing if var EMACS is already set # Extract the first word of "emacs", so it can be a program name with args. set dummy emacs; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_EMACS+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$EMACS"; then ac_cv_prog_EMACS="$EMACS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_EMACS="emacs" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi EMACS=$ac_cv_prog_EMACS if test -n "$EMACS"; then { $as_echo "$as_me:$LINENO: result: $EMACS" >&5 $as_echo "$EMACS" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "x$EMACS" = x ; then { { $as_echo "$as_me:$LINENO: error: emacs not found; required!" >&5 $as_echo "$as_me: error: emacs not found; required!" >&2;} { (exit 1); exit 1; }; } fi # Check whether --with-sitelisp was given. if test "${with_sitelisp+set}" = set; then withval=$with_sitelisp; sitelisp="$withval" else sitelisp="$datadir/emacs/site-lisp" fi badnamesp=true # Check whether --enable-badnames was given. if test "${enable_badnames+set}" = set; then enableval=$enable_badnames; test "$enableval" = no && badnamesp=false fi ac_config_files="$ac_config_files GNUmakefile doc/GNUmakefile lisp/GNUmakefile tests/GNUmakefile skram/GNUmakefile" ac_config_files="$ac_config_files tests/ebatch" ac_config_commands="$ac_config_commands symlinks" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by EDB $as_me 1.31, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ EDB config.status 1.31 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2008 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { $as_echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "GNUmakefile") CONFIG_FILES="$CONFIG_FILES GNUmakefile" ;; "doc/GNUmakefile") CONFIG_FILES="$CONFIG_FILES doc/GNUmakefile" ;; "lisp/GNUmakefile") CONFIG_FILES="$CONFIG_FILES lisp/GNUmakefile" ;; "tests/GNUmakefile") CONFIG_FILES="$CONFIG_FILES tests/GNUmakefile" ;; "skram/GNUmakefile") CONFIG_FILES="$CONFIG_FILES skram/GNUmakefile" ;; "tests/ebatch") CONFIG_FILES="$CONFIG_FILES tests/ebatch" ;; "symlinks") CONFIG_COMMANDS="$CONFIG_COMMANDS symlinks" ;; *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 $as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || { $as_echo "$as_me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=' ' ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` = $ac_delim_num; then break elif $ac_last_try; then { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\).*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\).*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 $as_echo "$as_me: error: could not setup config files machinery" >&2;} { (exit 1); exit 1; }; } _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 $as_echo "$as_me: error: Invalid tag $ac_tag." >&2;} { (exit 1); exit 1; }; };; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 $as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} { (exit 1); exit 1; }; };; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac ac_file_inputs="$ac_file_inputs '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` { as_dir="$ac_dir" case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 $as_echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p ' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } ;; :C) { $as_echo "$as_me:$LINENO: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "tests/ebatch":F) chmod +x tests/ebatch ;; "symlinks":C) exdir="${srcdir}/examples" test -L "$exdir/passwd" || ln -s /etc/passwd "$exdir" test -L "$exdir/null" || ln -s /dev/null "$exdir" ;; esac done # for ac_tag { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 $as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:$LINENO: WARNING: Unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2;} fi # configure.ac ends here edb-1.31/install-sh0000755000175000017500000003246410770154661012410 0ustar ttnttn#!/bin/sh # install - install a program, script, or datafile scriptversion=2006-12-25.00 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # 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. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # 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 $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: edb-1.31/doc/0000755000175000017500000000000011016452347011134 5ustar ttnttnedb-1.31/doc/edb.info0000644000175000017500000102713711016452257012556 0ustar ttnttnThis is edb.info, produced by makeinfo version 4.11.96 from edb.texi. INFO-DIR-SECTION Emacs START-INFO-DIR-ENTRY * EDB: (edb). The Emacs Database. END-INFO-DIR-ENTRY Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation.  File: edb.info, Node: Top, Next: Introduction, Up: (dir) EDB Manual ********** EDB is the Emacs Database. This file is the 2008-05-26 Edition of the EDB Manual, corresponding to EDB 1.31. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. * Menu: * Introduction:: User Manual * Database mode:: * Database View mode:: * Database Edit mode:: * Searching:: * Sorting:: * Database Summary mode:: * Marking and hiding:: * Reports:: * Specifying the display format:: Programmer Manual * Specifying control:: * Record field types:: * Database file layout:: * How information is displayed:: * Customization:: * Database representation:: * Naming conventions:: * In case of trouble:: Indices * Function Index:: * Variable Index:: * Concept Index:: --- The Detailed Node Listing --- Introduction * Organization of this manual:: * Terminology and concepts:: * Invoking EDB:: * Example EDB session:: Database View mode * Moving around in the database:: * Changing to Database Edit mode:: * Undoing all changes to a record:: * Making changes permanent:: * Adding and removing records:: * Exiting database mode:: Database Edit mode * Exiting Database Edit mode:: * Undoing changes to a field:: * Moving from record to record:: * Moving from field to field:: * Movement within a field:: * Editing a field:: * Getting help:: Sorting * Sort interface:: * Sorting functions:: Marking and hiding * Setting the mark and hide bits:: * Movement among marked and hidden records:: * Details of hiding:: Specifying the display format * Changing display formats:: * Execution of format file eval expressions:: * Making additional data display buffers:: Specifying control * Interpreting control properties:: * Kinds of control property values:: * Control properties reference:: * New control example:: * Ongoing migration:: * Changing control properties at runtime:: * Example control file from scratch:: Record field types * Specifying a record field type:: * Predefined record field types:: * Record field attributes:: Database file layout * Data encoding:: * Internal file layout:: * Delimited file layout:: * Tagged file layout:: * Relational file layout:: * Nonregular file layout:: * Reading from disk:: Delimited file layout * How to specify delimited file layouts:: * Resolving ambiguities:: * Problems with end-of-file newlines:: Nonregular file layout * Nonregular database example:: How information is displayed * Display specifications:: * Predefined displaytypes:: * Enumeration displaytypes:: * Defining new displaytypes:: * Display specification optional parameters:: Customization * Auxiliary files:: * Hooks and customization functions:: * Global variables:: Hooks and customization functions * Read hooks:: * Database mode hooks:: * Record display hooks:: * Edit mode hooks:: * Display format change hooks:: Database representation * Mapping over the database:: * Manipulating records::  File: edb.info, Node: Introduction, Next: Database mode, Prev: Top, Up: Top 1 Introduction ************** EDB is a database program for GNU Emacs. It permits you to manipulate structured (or not-so-structured) data within Emacs and provides many of the usual database features, including: * Flexible, customizable file layouts. Data may contain any character, including those used to delimit fields and records. Files read and written by the database may have arbitrary formats. * Typed fields (e.g. integer, date, string); fields may also be subject to additional constraints (prime number, date before today, string that appears in some other record, etc.). * Arbitrary data display formats for viewing records. Multiple display formats can be open on a database simultaneously, viewing the same or different records. The data display format can be automatically chosen based on the record's field values. * Selective display of only those records of interest; others become temporarily invisible. * Standard GNU Emacs editing commands, which work only within data fields and not on the surrounding text. * Database summaries, which show in a single buffer one or more lines of information about each record. * Sorting, with an easy-to-use interface for defining the sorting criteria; most sorting orders you would care about are easy to specify, but arbitrary ones are also permitted. * Merging and reconciliation of databases. * Reports generated from database information. * Highly customizable via the underlying programming language, Emacs Lisp; many hooks and useful variables are provided to make this even easier. EDB is more ambitious -- and therefore more complex -- than its forerunners (such as Forms Mode by Johan Vromans ). While other packages don't provide as much functionality as EDB, they may be more appropriate for simple needs. While EDB provides sophisticated functionality and is extensively customizable, it is not as powerful as some other database systems, and does not directly qualify as either "relational" or "object-oriented." On the other hand, EDB may well meet your needs without being buzzword-compliant. (EDB extensions to provide a subset of the features of a relational or object-oriented database can and have been written.) * Menu: * Organization of this manual:: * Terminology and concepts:: * Invoking EDB:: * Example EDB session::  File: edb.info, Node: Organization of this manual, Next: Terminology and concepts, Up: Introduction 1.1 Organization of this manual =============================== This manual contains two major parts. The first part describes how to use EDB to manipulate an existing database, and the second part describes how to design a new database. The first part -- which could be called the EDB User Manual -- first presents basic commands such as loading a database into memory, adding, deleting, and modifying records, and searching; then it describes more advanced features such as sorting, displaying record summaries, marking or ignoring certain records, and producing reports. The second part -- which could be called the EDB Programmer Manual -- describes the three forms that database information can take: when being manipulated by EDB, when stored on disk, and when displayed on the screen. Separate chapters discuss specifying each of these representations. The manual then goes on to discuss customization hooks and explains some of the lower-level implementation details that an advanced programmer may need to know. Note that these implementation details may change or disappear entirely, after first becoming undocumented. Such cases are marked with `Documentation for FOO is to be deleted by EDB X.Y', where X.Y is a version number of a future EDB release.  File: edb.info, Node: Terminology and concepts, Next: Invoking EDB, Prev: Organization of this manual, Up: Introduction 1.2 Terminology and concepts ============================ A "database" is a collection of "records" kept in memory, each of which is comprised of various "fields". A record's fields are usually all related to some central object or concept; for instance, they might describe various information about a particular person such as name, address, and phone number. A field's meta-information -- for example name, default value, methods for representing the value between memory/disk/display contexts, behavior on update, constraints, and so on -- is collectively called its "fieldtype". All records of a database have the same structure (the number and order of the fieldtypes are the same), though typically different records have different information in the fields. EDB permits database records to be viewed, edited, and manipulated in a structured way. When a database is "in memory", there is at least one "data display buffer" associated with it, showing a single record -- the "current record" -- using a particular "display format". This buffer can be in Database View or Database Edit mode. A display format is a template, comprising "inter-field text" embedded with at least one "display specification" ("displayspec", for short). The displayspec associates a field name with a "displaytype", which controls how a particular fieldtype is to be rendered in a buffer (inter-field text is rendered as-is). Each data display buffer may have a dependent "summary buffer" showing selected fields of all records. Moving from one record to another in the summary buffer updates the data display buffer to synchronize the current record. (However, moving in the data display buffer does not update the summary buffer.) Killing a data display buffer kills its associated summary buffer (if any), although the reverse is not true. When the last data display buffer associated with a database is killed, EDB forgets the database; it is no longer in memory. Collectively, all the information outside of the data proper -- display formats, fieldtypes, and so on -- is called the "control", to borrow the hardware designer's terminology and awareness of the duality of control signals versus datapath: If we believe in data structures, we must believe in independent (hence simultaneous) processing. For why else would we collect items within a structure? Why do we tolerate languages that give us the one without the other? --Alan Perlis [I believe Perlis is saying that the computation model for hardware, where everything happens in parallel, is pretty interesting. Maybe EDB is not so interesting, but that's just a SMOP away... --ttn]  File: edb.info, Node: Invoking EDB, Next: Example EDB session, Prev: Terminology and concepts, Up: Introduction 1.3 Invoking EDB ================ To use EDB, you need to establish a connection to a control source and a data source, the former describing how EDB should handle the latter, either with the command `edb-interact', or with the command `db-find-file'. The first command made its debut in EDB 1.26 and is destined to evolve towards its final form for EDB 2.x; it is recommended over the second one for reasons too complicated to explain here (*note Reading from disk::, instead). Suffice to say that the `db-find-file' approach will not be available in EDB 2.x. In either case, to arrange for the commands to be autoloaded, add this form to your `~/.emacs' file: (let ((el "database") (blurb "Emacs Database")) (autoload 'edb-interact el blurb t) (autoload 'db-find-file el blurb t)) Now, when you start up Emacs, you will already be able to execute `edb-interact' and/or `db-find-file'; EDB will be loaded automatically. 1.3.1 Connecting with `edb-interact' ------------------------------------ Control information is usually saved in a file, but may also be taken directly from the current buffer. This "control file" (or perhaps "control buffer" as the case may be) is the first argument to the command `edb-interact'. The second argument specifies the data file. -- Command: edb-interact control data Open a connection to the CONTROL (.edb) and DATA files. CONTROL may be a buffer whose contents are to be parsed as a `.edb' file. DATA may be nil, in which case the EDB searches for a file whose stem is the same as CONTROL's (or its `buffer-file-name' if CONTROL is a buffer), with extension one of `.data', `.dat', or the empty string (no extension), in that order. Once the connection is open, read in DATA and switch to the data display buffer. However, if DATA is already in memory, simply switch to its (first) data display buffer. You can use a properly constructed control file (or buffer) with multiple data sources. To create a new database, the easiest way is to copy one of the `.edb' files in the distribution and adapt it to your needs. *Note New control example::, for an example. 1.3.2 Connecting with `db-find-file' ------------------------------------ You need three files to run EDB the "old" (1.x only) way: a data file, a format file, and an auxiliary file. The data file (usual suffix `.dat') contains the information that makes up the database. The format file (usual suffix `.fmt') specifies how the fields of a particular record appear in the data display buffer, where you may view or edit one record at a time. The auxiliary file (usual suffix `.dba') contains additional information about the database, such as the number of fields in each record, the layout of the data file (including what characters or strings serve as field and record separators), customizations, etc. A fourth type of file is the report format file, which is a format file used in generating reports printed on the screen, to a file, or to a printer; *note Reports::. Different databases may share format and auxiliary files. For examples of data, format, and auxiliary files, see the `examples' subdirectory of the EDB distribution. You can combine the format and auxiliary files (by placing the auxiliary file information at the end of the format file, in the local variables section), but for simplicity we will consider the two files separately. There may be many different ways to lay out a record on the screen, so a database could have many different format files; for the time being we will concentrate on the format file which is used first, which is called the primary format file, even though it might not be the one that is used most often. When invoking the database, you typically only need to name the data file; the names of the others are inferred from its name (*note Auxiliary files::) or may be mentioned explicitly by it. The `db-find-file' command loads the database into memory: -- Command: db-find-file [filename [promptp]] Read a database from FILENAME. If the database file doesn't specify a format and the format file can't be inferred from FILENAME, then prompt for it, too. Always prompt for the format file if prefix argument PROMPTP is non-`nil'. If the database is already read in and PROMPTP is `nil', the existing database buffer is merely selected. When called non-interactively, argument PROMPTP may be a string, the name of a format file to use. You can use `db-save-database' and `db-write-database-file' (normally bound to `C-x C-s' and `C-x C-w', respectively, in Database View mode) to save databases in memory to the file from which they were read or to an arbitrary file.  File: edb.info, Node: Example EDB session, Prev: Invoking EDB, Up: Introduction 1.4 Example EDB session ======================= Here is a small tutorial that steps through a typical EDB session: connecting to a single control and a single data source, moving from record to record in the data display buffer, creating a summary buffer, sorting the records, writing the changed data (if any) to disk, and finally disconnecting. Each step is a command or a series of commands to type into Emacs (sometimes with trailing implied). Additionally, you can type `C-h m' in each of the buffers for more information. `C-x C-f skram/retired.edb' `M-x edb-interact' This visits a control file in the distribution and initiates a connection. You can simply type when Emacs asks for the control file (at the first prompt) to use the current buffer. Note that you could have specified the control file directly to `edb-interact' without visiting it; we present it in two steps to give you a chance to look over its contents. The distribution also includes the file `retired.data' in the same directory, so you can type when Emacs asks for the data source (at the second prompt) to have EDB find it automatically. Once the data is in memory, Emacs switches to its data display buffer, which is in Database View mode, which is read-only and does not permit editing. *Note Database mode::, *Note Database View mode::. `n' `p' These update the buffer with the next or previous record, respectively. *Note Moving around in the database::. `TAB' `C-n' This moves point to the first field and switches to Database Edit mode. *Note Changing to Database Edit mode::, *Note Database Edit mode::. Once you are on a field, printing characters insert themselves and the other usual editing commands work as well. `TAB' moves to the next field, and `C-n' moves to a field on the next line (or to the next line of this field, if it spans multiple lines). *Note Moving from field to field::, *Note Movement within a field::. `M-TAB' `C-p' Like `TAB' and `C-n', but move backward by fields or lines. `C-c C-c' This returns to Database View mode from Database Edit mode. If you made any changes, you can type now to accept the changes, or `C-x u' to undo them. `h' This displays a summary (also known as "headers") of all the records of the database. You can move around in the summary buffer using ordinary movement commands, and the record under point will be displayed in the data display buffer. Use `v' or `e' to return to the data display buffer; `v' puts you in Database View mode and `e' puts you in Database Edit mode. *Note Database Summary mode::. `S' (Note: uppercase.) From Database View mode, this invokes the database sort interface, which permits easy specification of how records should be sorted. Type `M-n' and `M-p' to drag a field up (more important) or down (less important). Type to perform the sort and return to the data display buffer. *Note Sorting::. `C-x C-s' This saves to disk any changes you have made to the data. `+' This creates a new data display buffer. `x' This kills the current data display or summary buffer. In the latter case, Emacs switches to the associated data display buffer. You are offered the chance to save the changes you have made. For invocation with `db-find-file', the tutorial is still applicable if you use `M-x db-find-file examples/forms-demo.dat' for the first step instead of the `C-x C-f' and `M-x edb-interact'.  File: edb.info, Node: Database mode, Next: Database View mode, Prev: Introduction, Up: Top 2 Database mode *************** A single database record (typically the "current record") is viewed in a data display buffer.(1) The layout and formatting of the data display buffer -- where and how the fields of the current record are shown, and what fixed explanatory text surrounds them -- is specified by a data display format. Only the database fields can be edited; the explanatory text is fixed. *Note Specifying the display format::, to create a new data display format. *Note Making additional data display buffers::, to create a new data display buffer (with the same or a different data display format). *Note Database Summary mode::, to view summary information about all database records at once. Database mode has two basic submodes, Database View mode (*note Database View mode::) and Database Edit mode (*note Database Edit mode::). These modes are used, respectively, when examining or manipulating records and when changing information in a particular record. Keystrokes have different meanings in these two modes. In Database View mode no editing may be done, and many printable characters are redefined to make manipulation of the database easy (for instance, `n' moves to the next record). In Database Edit mode a field of the current record is being edited; most printable keys insert themselves, and other editing and movement commands work in the ordinary way. In the data display buffer, where database records are ordinarily viewed and edited, one of these two modes is always in effect. (You may be tempted to directly edit a raw database file in its on-disk layout. Do so at your own risk, and never change a database buffer out of Database mode.) The mode line indicates which mode you are in. It looks something like: -***- machine-dbase (Database Edit Abbrev 42/431)---All------------ The mode line consists of three modification indicators, the name of the database file being manipulated (in this case, `machine-dbase'), mode information within parentheses, and the usual percentage-of-screen-visible indicator. The mode information consists of the database submode (such as View, Edit, or Summary), any minor modes which are turned on (such as Abbrev mode), the number of the current record, and the total number of records in the database. Ordinarily the Emacs mode line contains only one modification indicator consisting of two dashes (not modified), asterisks (modified), or percent signs (read-only). The EDB mode line contains three modification indicators, one each for the database, the displayed record, and the current field. The field indicator is `*' if the field under point has been modified, `-' if it has not, and `%' if it is read-only or if no field is under point (for instance, if the data display buffer is in Database View mode rather than Database Edit mode). The database is modified only when a changed record is written into it; changes to the current record do not immediately affect the database proper. This permits such modifications to be conveniently undone. *Note Undoing all changes to a record::. *Note Making changes permanent::. Thus, the displayed record may be modified without the database being modified, since the database is considered modified only when the current record has been processed and the resulting value placed in the database. A similar situation exists for the current field of the current record. (*Note Undoing changes to a field::.) Do not attempt to directly change the major mode of a database buffer. If a database buffer is placed in another mode, the database functions will cease working (they refuse to operate on non-database buffers, since the consequences of such action could be severe); for instance, you may be unable to save any of your work due to errors raised while EDB tries write to its buffers to disk. Furthermore, EDB makes assumptions about where point is located in Database View and Database Edit modes; violating these can cause changes to the current record to be lost. ---------- Footnotes ---------- (1) The data display buffer was previously called the format buffer; this is why all of the variables and functions relating to it start with the `dbf-' prefix.  File: edb.info, Node: Database View mode, Next: Database Edit mode, Prev: Database mode, Up: Top 3 Database View mode ******************** The data display buffer is in Database View mode whenever field information is not being edited. Most commands to move from record to record and to manipulate records (sorting, printing reports, showing summaries, etc.) are performed in Database View mode. Basic operations are described here; more complicated ones, such as searching (*note Searching::), are given sections of their own. * Menu: * Moving around in the database:: * Changing to Database Edit mode:: * Undoing all changes to a record:: * Making changes permanent:: * Adding and removing records:: * Exiting database mode::  File: edb.info, Node: Moving around in the database, Next: Changing to Database Edit mode, Up: Database View mode 3.1 Moving around in the database ================================= `n' -- Command: db-next-record [arg] Go to the ARGth next record. In that record, go to the current field, if any. `p' -- Command: db-previous-record [arg] Go to the ARGth previous record. In that record, go to the current field, if any. `<' `M-<' -- Command: db-first-record [arg] Show the database's first record. With optional prefix argument, ignore hiding. `>' `M->' -- Command: db-last-record [arg] Show the database's last record. With optional prefix argument, ignore hiding. `j' -- Command: db-jump-to-record arg [respect-hiding] Show the database's ARGth record. Hiding is ignored unless optional argument RESPECT-HIDING is specified. There are two special hybrid commands that show more of the current record if there's more to see and otherwise show the next (or previous) record. `' -- Command: db-next-screen-or-record [arg] Go to the ARGth next screenful of this display, or to the ARGth next record, if this is the last screenful of this display. If point is in the summary buffer and the data display buffer is not visible, then move to the next record. `' -- Command: db-previous-screen-or-record [arg] Go to the ARGth previous screenful of this display, or to the ARGth previous record, if this is the first screenful of this display. If point is in the summary buffer and the data display buffer is not visible, then move to the previous record.  File: edb.info, Node: Changing to Database Edit mode, Next: Undoing all changes to a record, Prev: Moving around in the database, Up: Database View mode 3.2 Changing to Database Edit mode ================================== When in Database View mode, you cannot edit the fields of the record being displayed. In order to do so, change to Database Edit mode and move to the field you wish to edit. You can click the mouse on the field you wish to edit, or move to the first or last field (and from there to the desired field) via the following keystrokes: `TAB' `C-n' `e' -- Command: db-first-field Move to first field. `C-p' `M-TAB' -- Command: db-last-field Move to last field.  File: edb.info, Node: Undoing all changes to a record, Next: Making changes permanent, Prev: Changing to Database Edit mode, Up: Database View mode 3.3 Undoing all changes to a record =================================== `C-x u' -- Command: db-revert-record Set the record to be the same as the corresponding one in the database. In other words, undo any changes made since entering this record. `C-x r' -- Command: db-revert-database Replace the database in memory with the data on disk. This undoes all changes since the database was last saved. You can also undo changes to the current field; *Note Undoing changes to a field::.  File: edb.info, Node: Making changes permanent, Next: Adding and removing records, Prev: Undoing all changes to a record, Up: Database View mode 3.4 Making changes permanent ============================ You edit a copy of a database record; the database itself is not changed until you commit the changes. This occurs automatically whenever any command causes a different record to be displayed, when the database is saved, when a report is generated, and so forth. It does _not_ occur when you switch from Database Edit mode to Database View mode, though the field modification flag (in the mode line) will become a percent sign and the record modification flag, an asterisk. When the record is committed, the record modification flag becomes a dash and the database modification flag becomes an asterisk. You can manually install the current record, as modified, into the database. `' -- Command: db-accept-record Install the current record in the database; make any changes permanent. Committing a record makes the changes permanent only insofar as they become part of the in-memory representation of the database. The on-disk version is not affected unless you overwrite it by using `save-buffer' or `write-file', or otherwise indicate that the database should be written to disk (say, by responding affirmatively to a question about saving the database).  File: edb.info, Node: Adding and removing records, Next: Exiting database mode, Prev: Making changes permanent, Up: Database View mode 3.5 Adding and removing records =============================== `a' `i' -- Command: db-add-record [append] Add a new record to the database immediately before the current record. Prefix arg APPEND means to add after the last record, instead. After adding, move point to the new record's first field and switch to Database Edit mode. `c' -- Command: db-copy-record [arg] Insert a copy of the current record in the database immediately after it. The second of the two records is made the current record. With a prefix argument, inserts that many copies. `o' -- Command: db-output-record-to-db database Copy (output) the current record to DATABASE. DATABASE must be read in and compatible with the current database. `d' `k' -- Command: db-delete-record [arg] Remove the current record from the database. With a prefix argument, do not verify.  File: edb.info, Node: Exiting database mode, Prev: Adding and removing records, Up: Database View mode 3.6 Exiting database mode ========================= `q' -- Command: db-quit Quit editing the database for now; bury its buffers. `x' -- Command: db-kill-buffer [noask] Kill the data display buffer and any associated summary buffer. Offer to save any changes. Prefix arg means don't offer. `X' -- Command: db-kill-all-buffers [noask] Kill all buffers associated with the current database. Offer to save any changes. Prefix arg means don't offer. For backward compatability, there is also the command `db-exit'. -- Command: db-exit [kill] Be done with the database; like `db-quit', but offer to save any changes. With prefix argument, call `db-kill-all-buffers' after saving changes.  File: edb.info, Node: Database Edit mode, Next: Searching, Prev: Database View mode, Up: Top 4 Database Edit mode ******************** The database is "modifiable" if either it is a new database, not associated with any file, or if it is read from a file that is modifiable (i.e., satisfies `file-writable-p'). The database being not modifiable does not prevent you from entering Database Edit mode, only from making changes while in Database Edit mode. You can toggle or set this status bit with `db-toggle-modifiable-p', normally bound to `C-x C-q' in Database View, Database Edit, and Database Summary modes. -- Command: db-toggle-modifiable-p [arg] Toggle whether the database may be modified. With a nonzero prefix argument, set it modifiable. With a zero prefix argument, set it non-modifiable. The data display buffer is in Database Edit mode whenever a field of the current record is being edited. All printing characters insert themselves, and the usual editing commands can be performed on the field contents. It is also possible to move from field to field and from record to record, and to perform other operations on the database, though the commands available in Database View mode are richer. In Database Edit mode, point is always in the field currently being edited. The database is not modified as soon as changes are made in Database Edit mode. Rather, a copy of the record in question is displayed and edited, and only when you move to a new record, initiate some other global action (not specific to the edited record), or explicitly commit the changes (*note Making changes permanent::). This permits easier undoing of incorrect modifications. In order to perform most record-level operations, you switch to Database View mode, and then perform them there. Several commonly used commands, however, such as searching and moving from record to record, are accessible directly from Database Edit mode. Commands that move from field to field check the validity of the current field before moving off it; commands that move from record to record do this as well, then make any changes in the current record permanent (though the database file on disk is not changed). Basic operations are described here; more complicated ones are given sections of their own. * Menu: * Exiting Database Edit mode:: * Undoing changes to a field:: * Moving from record to record:: * Moving from field to field:: * Movement within a field:: * Editing a field:: * Getting help::  File: edb.info, Node: Exiting Database Edit mode, Next: Undoing changes to a field, Up: Database Edit mode 4.1 Exiting Database Edit mode ============================== `C-c C-c' -- Command: db-view-mode [arg] Switch to Database View mode. With an argument, toggle between Database View and Database Edit modes.  File: edb.info, Node: Undoing changes to a field, Next: Moving from record to record, Prev: Exiting Database Edit mode, Up: Database Edit mode 4.2 Undoing changes to a field ============================== You can undo changes to the current field via Emacs' usual undo facility; use `C-x u' or `C-_' to undo changes made since entering the current field. You can also revert the current field to its original value; this is useful if you made a change, moved off the field, and then moved back onto it. `C-x U' -- Command: db-revert-field Undo any changes made since entering this field. Replace the onscreen text in this field with that of the underlying record. A similar effect can be had by invoking `C-x u' multiple times. From Database View mode, you can simultaneously revert every modified field of a record to its original value; *Note Undoing all changes to a record::.  File: edb.info, Node: Moving from record to record, Next: Moving from field to field, Prev: Undoing changes to a field, Up: Database Edit mode 4.3 Moving from record to record ================================ The commands for moving to the next and previous records make any changes to the current record permanent. *Note Moving around in the database::.  File: edb.info, Node: Moving from field to field, Next: Movement within a field, Prev: Moving from record to record, Up: Database Edit mode 4.4 Moving from field to field ============================== `TAB' -- Command: db-next-field [arg] Move to ARGth next reachable field, wrapping if necessary. When called interactively, ARG defaults to 1. `M-TAB' -- Command: db-previous-field Move to ARGth previous reachable field, wrapping if necessary. When called interactively, ARG defaults to 1. `M-<' `M->' Move to the first or last field (*note Changing to Database Edit mode::). Also see the keystrokes `C-n' and `C-p', described below.  File: edb.info, Node: Movement within a field, Next: Editing a field, Prev: Moving from field to field, Up: Database Edit mode 4.5 Movement within a field =========================== All Emacs cursor motion commands retain their standard meanings, except that they do not move outside the field. The line-movement commands have slightly changed meanings: if the motion would take the cursor out of the current field, then they move to the next field. `C-n' -- Command: db-next-line-or-field [arg] Move to ARGth next line. If that would move out of the current field, move to the closest field to that, but not the current one, wrapping if necessary. `C-p' -- Command: db-previous-line-or-field [arg] Move to ARGth previous line. If that would move out of the current field, move to the closest field to that, but not the current one, wrapping if necessary.  File: edb.info, Node: Editing a field, Next: Getting help, Prev: Movement within a field, Up: Database Edit mode 4.6 Editing a field =================== Many Emacs editing commands retain their standard meanings; for instance, printing characters insert themselves and deletion commands work as usual, except that they do not make changes outside the field; among these are: `C-d' `delete-char' `' `backward-delete-char' `M-d' `kill-word' `M-' `backward-kill-word' `C-k' `kill-line'  File: edb.info, Node: Getting help, Prev: Editing a field, Up: Database Edit mode 4.7 Getting help ================ You can get some information about the current field, such as what type of value it expects or what its contents signify, by using the following command. `M-?' -- Command: db-field-help Display help for current field in the echo area.  File: edb.info, Node: Searching, Next: Sorting, Prev: Database Edit mode, Up: Top 5 Searching *********** A useful and commonly used database operation is searching for records that meet some criteria: for instance, finding a particular record or indicating that following operations should only apply to records that correspond to an address in greater Boston. EDB provides several functions to support such operations. 5.1 Search commands =================== To perform a search pertaining to the contents of only one field, move to that field and use the following command: `M-s' -- Command: db-search-field Search for occurrences of PATTERN in the current field of any record. Finds the first match after the current record; wraps around automatically. With prefix argument, marks all matches in addition to going to the first one. If hiding is in effect, hidden records are ignored. The same keystroke in Database View mode permits specification of patterns which depend upon the contents of several fields: `s' `M-s' `M-S' -- Command: db-search `db-search' is not yet implemented; use `db-search-field' instead. In a future version of EDB, `db-search' will permit searching on all fields of a record simultaneously. For a description of marking, *Note Marking and hiding::. 5.2 Search patterns =================== Search patterns can be as simple as a datum to match exactly or as complicated as the conjunction, disjunction, and negation of tests to be performed on field contents. 5.2.1 Basic patterns -------------------- A basic search pattern has the same form as the data that is kept in the field; for instance, to search in a string field for a particular string, use that string; to search for the date March 14, 1967, use `3/14/67' or `14 March 1967' or any other accepted date format. A basic pattern is treated somewhat more richly than a literal, however. In a string field, typing a string results in a match for any element which contains it as a substring; typing `ail', without the quotes of course, matches both `"ailment"' and `"fail"'. In a date field, `3/67' matches any date in March of 67, not just those March 67 dates which specifically exclude a day of the month. 5.2.2 Comparisons ----------------- A search pattern may also be a comparison prefix (<, >, or =) plus a datum which is treated exactly like any other element of that field. In a string field, `3/14' matches dates after March 14 in any year, and `=3/67' matches only dates in March 67 whose day of month is not specified. For more information about the interpretation of patterns, see the documentation for the particular types. 5.2.3 Logical connectives ------------------------- More complicated patterns can be built up out of simpler ones via the logical connectives AND, OR, and NOT. These work in the obvious way. One pattern which finds any date between the ides of March and Christmas, inclusive, is `> 3/14 AND < 12/26'; two patterns which find dates except March 14 are `NOT 3/14' and `< 3/14 OR > 3/14'. To find strings that either contain the substring `"ail"' or start with a, b, or c, use `ail OR < d'. The precedence of these connectives is: NOT, which is most tightly bound to its test, then OR, then AND. There are no provisions for grouping or otherwise overriding this ordering. Connectives (and REGEXP, described below) consume all surrounding spaces and tabs. 5.2.4 Other pattern operations ------------------------------ One other pattern operation of interest is the regexp operator for string fields. This is invoked by either using REGEXP with surrounding spaces, or / without a trailing space. For instance, `/^[ace]' matches any string field starting with a, c, or e; `/.' matches any nonblank string field; and `NOT REGEXP a.*b.*c' matches any string which does not contain the letters a, b, and c in order. This last example shows that EDB's search commands are more powerful than general regular expression searching.  File: edb.info, Node: Sorting, Next: Database Summary mode, Prev: Searching, Up: Top 6 Sorting ********* Sorting a database reorders its records without changing the contents of any particular record. For instance, it might be convenient to arrange an address database sometimes alphabetically by last name, sometimes by ZIP code, and sometimes by some other criteria. * Menu: * Sort interface:: * Sorting functions::  File: edb.info, Node: Sort interface, Next: Sorting functions, Up: Sorting 6.1 Sort interface ================== From a data display buffer in Database View mode, you can specify a particular record ordering using `db-sort'. `S' -- Command: db-sort [arg] Switch to the sort interface buffer. With a prefix argument, don't confirm the sort order. Ordinarily, calling this function invokes the sort interface, an easy-to-use tool for specifying which fields should be treated as sort keys, and in what order. In a database whose records have fields `firstname', `lastname', `address', `city', and `zip', and in which records should first be sorted on `lastname' in increasing order, then on `firstname' in _decreasing_ order, ignoring the other fields entirely for the purposes of the sort, the sort interface display would look like ==== Significant fields: lastname increasing firstname decreasing ==== Nonsignificant fields: address increasing city increasing zip increasing ==== Hidden records to end: No In addition to which fields should be sorted by, the sort interface permits specification of how hidden records should be treated. `t' -- Command: dbsi-toggle-hidden-to-end Toggle a flag that controls whether hidden records should all be placed at the end of the sorted order or should be sorted according to the same criteria as non-hidden records. To change the relative order of fields, and whether they're significant or not, use the following commands. `C-k' -- Command: dbsi-kill-line Move field on current line to the top of the nonsignificant list. This can also be used within the nonsignificant list to reorder it. `C-y' -- Command: dbsi-yank-line Yank the field from the top of the nonsignificant list. Insert it before the current line. Prefix arg means point doesn't move. `M-p' `M-n' In the list of significant fields, "drag" the field under point up (more important) and down (less important), respectively. To specify how a particular field should be ordered, use the following commands. `i' -- Command: dbsi-increasing Specify that the field at point should use an increasing ordering. `d' -- Command: dbsi-decreasing Specify that the field at point should use a decreasing ordering. `o' -- Command: dbsi-ordering-function Specify an ordering function for the field at point. An "ordering function" returns -1, 0, or 1 depending on whether its first argument is less than, equivalent to, or greater than its second argument. `s' -- Command: dbsi-sorting-function Specify a sorting function for the field at point. A "sorting function" returns `t' if its first argument is less than its second argument and `nil' otherwise. Each database has a default sort order specified by the `:field-order' control property (*note Control properties reference::), used when setting up the sort interface (and is used for sorting when no other ordering information is specified). When you exit the sort interface, the database's default ordering can be set to the ordering depicted on the screen (see below). Each data display buffer also has a default sort order; the database's default order is ignored if a local value is chosen using the sort interface. Setting the database's sort order automatically clears the local value. The following commands are used to exit the sort interface; most of them also cause the database to be sorted. Some of them set the default ordering for the database or the data display buffer. `' `C-c C-c' -- Command: dbsi-use-ordering-make-database-default Use the current ordering to sort, and make it the default for future sorts of this database. Display a warning if there are killed, non-yanked fields. `A' `U' -- Command: dbsi-use-ordering-make-buffer-default Use the current ordering to sort, and make it the default for future sorts in this data display buffer only. Display a warning if there are killed, non-yanked fields. `a' `u' -- Command: dbsi-use-ordering Use the current ordering for this sort only. `!' -- Command: dbsi-this-field-only Sort according to only the field at point. All editing of other fields is ignored. `q' -- Command: dbsi-quit Abort the sort and exit the sort interface (`dbsi-quit'). `c' -- Command: dbsi-quit-clear-buffer-default Clear the default sort order for this buffer and exit the sort interface without sorting. In the future, the default sort order will come from the database. The sort interface returns a field priorities list to be used when sorting. Sorting does not ordinarily mark the database as modified, because not the data itself, but only the way it is arranged, has been changed. If you set `db-sort-modifies-p' to non-`nil', then whenever a database is sorted (even if the resulting order is the same as the original one), the database is marked as modified. -- Variable: db-sort-modifies-p If non-`nil', then sorting a database marks it as modified too. When using control properties, you should use a `:locals' variable by the same name.  File: edb.info, Node: Sorting functions, Prev: Sort interface, Up: Sorting 6.2 Sorting and ordering functions ================================== In order to specify the relative order of two field values (for the same field, but from different records), you provide a sorting function, an ordering function, or both. If only one is provided, the other is automatically generated from it. In any event, only one of them is used for a given field on any particular sort. A sorting function takes two field values as arguments and returns `t' if its first argument is less than its second argument (that is, the first argument appears previous to the second in the sorted order). The sorting function returns `nil' if the arguments are equal or if the first argument is greater than the second (appears later in the sorted order). An ordering function, on the other hand, returns complete information about the relative order of its two arguments: it returns -1, 0, or 1 depending on whether its first argument is less than, equivalent to, or greater than its second argument. Use of an ordering function can result in fewer comparisons in some cases, because it returns more information. This is worthwhile if a significant amount of processing is required before the comparison is done. For example, suppose that two addresses are being carefully checked for equality and some of the steps leading up to that are expansion of abbreviations, standardization of spelling, capitalization, and spacing, etc.; then it is better to return the exact relative ordering than to possibly require another time-consuming operation to determine it. If it is possible to canonicalize the values beforehand, that may be even more efficient, but that is not always possible; consider the case of a small (but tedious to extract) part of the information in each field being compared.  File: edb.info, Node: Database Summary mode, Next: Marking and hiding, Prev: Sorting, Up: Top 7 Database Summary mode *********************** A summary is a listing containing abbreviated information about every record; it permits many records to be viewed at once. This is available in Database View mode via the following command: `D' `H' `h' -- Command: db-summary Display a summary (or directory) of all database records according to the value set by `dbf-set-summary-format'. The summary appears in a separate buffer. When called from the summary buffer, this updates the summary. When a summary is created, the summary display format appears in the summary buffer once for each record, with appropriate values substituted for its display specifications. The entire format is indented by two characters; the first and second columns contain `+' and `[', respectively, if the record is marked or hidden. *Note Marking and hiding::. *Note Details of hiding::. The summary buffer is not updated whenever a record value changes; in the interest of efficiency, it remains as is until the next `db-summary' command is issued, at which time the summaries are redisplayed after all, some, or none of them have been recomputed. For the same reason, when a single mark or hide bit changes, the summary is updated; when many change, it is usually not. When point is in the summary buffer, the associated data display buffer (nearly) always displays the record under point. (Some Emacs commands can move point without EDB noticing.) Movement in the summary buffer is by any of the ordinary Emacs commands, including searching. Most Database View mode commands also work in the summary buffer. The summary display format defaults to the first non-literal line in the database display format -- that is, the first line which contains a display specification. Summary display formats can display information any way that an ordinary display format can, including showing more than one field of the record in question or spanning several lines. The only restriction is that the summary display format must cover a specific number of lines: each display specification must have its `min-height' and `max-height' slots set to equal values. For more information about display formats, *Note How information is displayed::. The following command may appear in a format file or an auxiliary file, or it can be invoked directly. When it appears as an Emacs Lisp form, remember the special meaning of the backslash character and double it where necessary. -- Command: dbf-set-summary-format summary-format Specify the format used in the Database Summary buffer. Argument SUMMARY-FORMAT is a string containing display specifications. Call this in the data display buffer, or in a format file or auxiliary file.  File: edb.info, Node: Marking and hiding, Next: Reports, Prev: Database Summary mode, Up: Top 8 Marking and hiding ******************** The marking facility permits operations to be performed on only certain records of a database. For instance, to create a report which describes only some of the database records, you would first mark the records of interest. Then you would call `db-report' with a prefix argument (do so by pressing `C-u' first), or would make optional second argument MARKEDP non-`nil'. See the documentation of the individual operations to see whether they support operation on only the marked records. The hiding facility also restricts attention to a subset of the current database. It is similar to Outline mode in that it makes some records temporarily invisible. Hiding is useful when you wish to concentrate on a subset of the database without being distracted by other records that may be present. By default hidden records are skipped by the record-motion commands, excluded from searches and reports, and ignored by most other operations. Mark and hide bits are associated only with the in-memory version of a database; they are not saved when you save a database, and are always unset (boolean false) when a database is read in. (When a database is written to disk, although the disk version of the data does not contain the mark and hide information, that information is not lost from the working copy of the database.) This behavior is a feature, not a bug. Marking and hiding are intended to help you temporarily group database records for operations upon them; if there is information that cannot be recreated from a record's fields, then you should consider adding another field for that information. On the other hand, mark or hide criteria may be complicated. If such a pattern is used often, then you may wish to write a function to set the bits appropriately, which function could be bound to a keystroke or automatically executed when the database is read in. * Menu: * Setting the mark and hide bits:: * Movement among marked and hidden records:: * Details of hiding::  File: edb.info, Node: Setting the mark and hide bits, Next: Movement among marked and hidden records, Up: Marking and hiding 8.1 Setting the mark and hide bits ================================== Every record may be thought of as having a pair of bits or boolean values indicating whether it is marked and whether it is hidden. The most straightforward way to set these bits is to use an operation to mark, unmark, hide, or unhide a particular record; these are bound to keystrokes in Database View mode. `m' -- Command: db-mark-record Toggle whether the current record is marked. With a nonzero prefix argument, set it to be marked. With a zero prefix argument, set it to be unmarked. `O' -- Command: db-hide-record Change whether the current record is hidden. With a nonzero prefix argument, set it to be hidden. With a zero prefix argument, set it to be unhidden. The searching commands, when called with a prefix argument, mark each matching record (*note Searching::). Once all records of interest have been marked, through one or more marking and/or searching commands, unmarked records can be hidden from consideration. This is useful if you want to work on only a small number of records, or if specifying the records of interest is easier than specifying those not of interest: instead of hiding all the uninteresting records, simply mark the interesting ones, then use the following command to cause the unmarked ones to become hidden. -- Command: db-hide-unmarked-records Enable hiding, hide all unmarked records, and clear all mark bits. The converse operation transfers information from the hide bits to the mark bits. -- Command: db-mark-unhidden-records Mark all unhidden records. Also clears all hide bits. It is also possible to clear all the mark or hide bits. -- Command: db-unmark-all Clear the mark bit of every record. -- Command: db-unhide-all Clear the hide bit of every record. Generally, to set or clear either the mark or hide bits of an arbitrary record of a database, you need to obtain the appropriate "tag" with `edb-tag', passing it and the record to one of the functions described below. -- Function: edb-tag name db Return the tag object named NAME associated with database DB. For EDB 1.x, NAME can be one of the keywords: `:markedp' or `:hiddenp'. The tag object can be passed to `edb-tagp', `edb-tagx' and `edb-tag-'. -- Function: edb-tagp tag record Return t if RECORD has its TAG set. -- Function: edb-tagx tag record Set TAG for RECORD. -- Function: edb-tag- tag record Clear TAG for RECORD. For example, this function sets the mark bit on those records (*note Mapping over the database::) for which PREDICATE returns non-nil: (defun my-mark-if (predicate) (let ((mtag (edb-tag :markedp dbc-database))) (db-maprecords (lambda (record) (when (funcall predicate record) (edb-tagx mtag record))))))  File: edb.info, Node: Movement among marked and hidden records, Next: Details of hiding, Prev: Setting the mark and hide bits, Up: Marking and hiding 8.2 Movement among marked and hidden records ============================================ Ordinarily, record movement commands (those which move from one record to another) ignore hidden records, so that you never land on a hidden record. Marked records, on the other hand, are not treated specially by the record movement commands. The following Database View mode keystrokes permit you to move to hidden records or to move directly to marked records. `M-n' -- Command: db-next-record-ignore-hiding [arg] Go to the ARGth next record, ignoring omissions. That is, all records, even those which are hidden, are counted. `M-p' -- Command: db-previous-record-ignore-hiding [arg] Go to the ARGth previous record, ignoring omissions. That is, all records, even those which are hidden, are counted. `M-C-n' -- Command: db-next-marked-record [arg] Go to the ARGth next marked record. Hidden records are treated according to db-hide-p. `M-C-p' -- Command: db-previous-marked-record [arg] Go to the ARGth previous marked record. Hidden records are treated according to db-hide-p.  File: edb.info, Node: Details of hiding, Prev: Movement among marked and hidden records, Up: Marking and hiding 8.3 Details of hiding ===================== The "hidden" bit of each record has no effect unless "hiding is in effect". When hiding is not in effect, the values of records' hide bits are remembered, and they may still be set and unset, but they have no effect on any operations until hiding is once again in effect. Enabling hiding makes `Hide' appear in the mode line of the database buffer. The following operations work in either Database View mode or Database Summary mode. `M-o' -- Command: db-hiding-toggle [arg] Change whether hiding is in effect. With a nonzero prefix argument, turn hiding on. With a zero prefix argument, turn hiding off. This does not change the current hide-function, and a hide bit is always computed for each record, but hide bits have no effect on any operations if hiding is not in effect. `M-C-o' -- Command: db-toggle-show-hidden-records [arg] Toggle whether hidden records are shown in the summary. With a nonzero prefix argument, show hidden records in the summary. With a zero prefix argument, don't show hidden records in the summary. `M-O' -- Command: db-hiding-set Set the criteria for automatically determining whether to hide a record. This isn't implemented yet.  File: edb.info, Node: Reports, Next: Specifying the display format, Prev: Marking and hiding, Up: Top 9 Reports ********* Reports can be generated from a database by using the following command in view mode: `r' -- Command: db-report [report-filename [markedp]] Create a report according to REPORT-FILENAME. Prefix argument MARKEDP, if non-`nil', means report on only marked records. If hiding is in effect, hidden records are not reported upon. When called interactively, prompts for REPORT-FILENAME. The way a report looks is specified in precisely the same as are display formats and summary formats (*note How information is displayed::). This information must be placed in a file; you cannot type it directly when creating a report. This restriction makes errors in the report format easier to correct. The report is placed in the `*Database Report*' buffer, which is in Text mode. The information may then be edited, saved to disk, or otherwise manipulated. The buffer is in Text mode and is not yet a file; you must save it to make it a file. To create a report which mentions only marked records (*note Marking and hiding::), supply a prefix argument to the report command by typing `C-u' first.  File: edb.info, Node: Specifying the display format, Next: Specifying control, Prev: Reports, Up: Top 10 Specifying the display format ******************************** Different layouts and on-screen arrangements of the values stored in database records are appropriate when you are concentrating on different aspects of the data. Sometimes you prefer to see just a few of the fields; at other times you may want to see the records in full detail. It may also be appropriate for the display format of a record to depend on the record's field values. This section describes how to choose a different display format for the record being displayed, either manually or automatically. * Menu: * Changing display formats:: * Execution of format file eval expressions:: * Making additional data display buffers::  File: edb.info, Node: Changing display formats, Next: Execution of format file eval expressions, Up: Specifying the display format 10.1 Changing display formats ============================= EDB permits the creation and use of a variety of display formats with a single database; you can also conveniently change the way that a particular record is displayed by using `db-change-format' and specifying the filename of the new display format, or a nickname for the format that has been assigned either during the session or before-hand. Choosing a different format does not create a new data display buffer; it changes the way that records are displayed in the current one. -- Command: db-change-format [format-name [filename]] Select and use an alternate display format to view the database. If neither FORMAT-NAME nor FILENAME is specified (as is the case when this is called interactively), then prompt for them. In Emacs Lisp code, if `dbf-format-name-spec-alist' has been been set, usually only one of the arguments is specified. If both are specified, then FORMAT-NAME becomes a name for the format FILENAME specifies; if FORMAT-NAME is already associated with a different format file, an error is signalled. If the current format is unnamed, then prompt for a name to give it, so that it can be conveniently restored if need be. This behavior is suppressed, and the record is not displayed, if the function is not being called interactively. The data display buffer is left in Database View mode. Selecting the current format does not cause any work to be done. Some databases automatically set the format of the record being displayed, usually by setting `dbf-before-display-record-function' to a function that overrides the format in effect when a record is about to be displayed. This may cause this function to appear not to be doing any work. In actuality the format is being set, then reset. -- Variable: dbf-format-name-spec-alist Association list of format names and format specifiers. Each format name is an arbitrary string. A format specifier is a filename or format file specifier, which is a list of values for format variables. When the format specifier is a filename, after that format file has been read, EDB replaces the filename with a list of values for format variables, so that the file need not be read again. This variable is set automatically for each `:display' control property specified (*note Control properties reference::). If there is only one `:display' and it is without a name, its name is taken as `t'. These values can be set in the auxiliary or format files so that you can choose a format name (with completion) instead of having to remember a filename. If the selected format's specifier is a filename, then after the file is read in, the format-spec is modified by replacing the filename with information about the format such as the displayspecs, the invariant text between them, and so forth. Subsequent selections of that format do not cause disk accesses. For an example of the use of `db-change-format', *Note Record display hooks::. While it is not currently possible to selectively hide certain fields from a data display buffer, judicious use of alternate formats can result in nearly the same effect.  File: edb.info, Node: Execution of format file eval expressions, Next: Making additional data display buffers, Prev: Changing display formats, Up: Specifying the display format 10.2 Execution of format file eval expressions ============================================== Often the local variables section of a format file contains code that should only be executed once, or should only be executed before the database is read in, because of either efficiency or correctness constraints. Because of this, the local variables section of a format file is executed only when it is read in from disk (which is usually only once). In order to cause an expression to be evaluated every time that a particular display format is selected, use the `dbf-always' macro: -- Macro: dbf-always [body...] Execute forms in BODY, and arrange to execute them in the future each time that this format replaces another. Of course, it is often valuable to overwrite a value when the display format changes; this is the purpose of `dbf-always'. It is always safe to set variables whose name begins with `dbf' in such forms, though changes to some such values will not take effect when a display format is being returned to (though they will work when it is first chosen). This will affect you only in that a call to `dbf-set-summary-format' will have an effect only the first time that a format file is read in, not every time that it replaces another, even if it is enclosed in a `dbf-always' form. The `dbf-always' forms are not executed every time that a record is displayed, or even every time that `db-change-format' is called, but only when a format replaces another one (that is, `db-change-format' is called and its first argument is not equal to the name of the current format). Here is an example of a common problem with an expression which causes an error if evaluated every time that the format is selected. The primary format file (the one that is used when the database is read in) is permitted to define the fields (names and types) of the database; other parts of the database initialization code propagate that information into other parts of EDB, caching and transforming things in the process. If you switch to another display format and back to the primary one, and the the field names have been re-initialized to their original forms again, then the next attempt to access this information (expecting a pre-transformed object) would cause an error. In this case, the proper solution is to use `database-set-fieldnames-to-list' (*note Specifying a record field type::) instead, but such functions are not provided for every slot that it would be dangerous to set. If several format files all set a value which is dangerous to change, then another possibility is to check the value before setting it: if it is already set, then don't do anything. Another possibility is to move all assignments to database slot values from the format file to the auxiliary file.  File: edb.info, Node: Making additional data display buffers, Prev: Execution of format file eval expressions, Up: Specifying the display format 10.3 Making additional data display buffers =========================================== In addition to changing the display format of an existing data display buffer, it is sometimes useful to have two different data display buffers both examining the same database, either so that two different records can be viewed or edited simultaneously or so that two different formats can be used at the same time -- or both. Use the following function (normally bound to `+' in Database View mode) to create a second (or additional) data display buffer for the current database. -- Command: db-additional-data-display-buffer Create another data display buffer in which to view this database. If you edit the same record in more than one data display buffer, only the last one committed (by calling `db-accept-record', moving to another record, saving the database, etc.) has an effect. (Simply switching from Database Edit mode to Database View mode does _not_ commit the changes; failing to commit changes makes it appear that changes in one data display buffer are not being communicated to the other ones associated with the same database. For more on committing, *Note Making changes permanent::.) It is perfectly safe, however, to edit different records of the same database in different data display buffers, or to perform any other database manipulations. To learn about formatting directives and specification of display format files, *Note How information is displayed::.  File: edb.info, Node: Specifying control, Next: Record field types, Prev: Specifying the display format, Up: Top 11 Specifying control ********************* The control for a particular data source comprises several different types of specification, describing all aspects of the data with respect to a connection session: its shape in abstract, its internal relationships, its representation outside of Emacs, its representation in an Emacs buffer, and various other meta-data. These are collectively known as the "control properties", most of which must be specified in the process of making a connection, by grouping them into a control file (or buffer) that begins with the magic text: :EDB (single BASIS) ;;; -*- emacs-lisp -*- Actually, the `;;; -*- emacs-lisp -*-' is optional; it is sufficient that on the first non-comment, non-blank line, the first four characters are colon and `EDB', followed by a space followed by a list whose first element is the name of a supported "schema-schema". At the moment (for EDB 1.x), the unique available schema-schema, and the subject of the rest of this manual, is `single'. Also, not all control can yet be specified with control properties; some "normal" Emacs Lisp variables and functions are still required. *Note Ongoing migration::. BASIS is an optional variable name (symbol) whose value specifies in property list form a set of control properties that are to be used as the basis -- i.e, elaborated (*note Interpreting control properties::) first -- for those specified in the rest of the buffer. This is useful for collecting in one place properties that are shared by many databases. * Menu: * Interpreting control properties:: * Kinds of control property values:: * Control properties reference:: * New control example:: * Ongoing migration:: * Changing control properties at runtime:: * Example control file from scratch::  File: edb.info, Node: Interpreting control properties, Next: Kinds of control property values, Up: Specifying control 11.1 Interpreting control properties ==================================== The way EDB processes a control file is designed so that you can express control properties primarily declaratively, while still permitting arbitrary computation, all in one place. Besides the magic header (*note Specifying control::), the rest of the control file contains, at the top-level, a mix of free-standing Lisp, and alternating control property names (keywords) and their associated "values-producing forms". Unlike `load' (or `load-file'), which can be described as a straightforward read-eval loop, control file processing is a bit more complicated. Specifically, EDB: 1. Checks the magic. 2. Parses the buffer using `read' and some helper funcs, accumulating the free-standing Lisp separately from the control properties. The helper funcs transform the text blocks associated with certain control properties into a plist. For example, given a buffer fragment: :display t first second :EOTB Then parsing yields the form (associated with `:display'): (:name t :coding t :EOTB "EOTB" :text "first\nsecond\n") 3. Evaluates, in order, the free-standing Lisp. 4. Validates the syntax of the control properties. 5. "Elaborates" the form associated with each control property, to get the actual control property values, and superficially checks these values. The elaboration method depends on the form: * A list whose CAR is a string is used directly. * A list whose CAR is a keyword is used directly. * For all other cases, `eval' the form. This allows (certain) control property values to be computed at connection time. For example, here are two equivalent ways to set the `:fields' control property: ;;; first way: literal :fields [time place] ;;; second way: computed :fields (vector 'time 'place) Here is another example which shows four functionally-equivalent ways to set the `:write-record' control property: ;;; first way: external function (require 'my-edb-setup) :write-record 'my-write-record ;;; second way: defun (defun my-write-record (time place) ...) :write-record 'my-write-record ;;; third way: defun integrated into decl :write-record (defun my-write-record (time place) ...) ;;; fourth way: lambda (the ultimate) :write-record (lambda (time place) ...) Although the ways are functionally equivalent, each has its consequences. The first way allows you to use a byte-compiled function (presuming it is defined in `my-edb-setup.el' and you byte-compile that file). Furthermore, once `my-edb-setup.el' provides (or arranges to provide) feature `my-edb-setup', it is no longer loaded on subsequent connections. Contrast this with the second and third way, which redefine `my-write-record' on every connection. The first three ways allow a breakpoint to be set (using `edebug', for example) on the function. The fourth way avoids burdening the already-crowded Emacs namespace by making use of an anonymous function. 6. Saves the control properties (how and where presently not described in this manual, but maybe in the future...).  File: edb.info, Node: Kinds of control property values, Next: Control properties reference, Prev: Interpreting control properties, Up: Specifying control 11.2 Kinds of control property values ===================================== This section describes some characteristics common to the values of certain control properties. (We resist using the term "type" here because that term is extremely overloaded in EDB, Emacs, and indeed throughout all of computer science and programming.) * Some properties (for instance, `:write-record') specify a function whose "arglist specifies field names". That is, the values of the specified fields of the current record are bound to function parameters with the same name. * Some properties (for instance, `:display') specify a "text-block specification", which is either a plist that specifies how to further process inline data, or `t' which expands to the default spec. Properties of the plist are: `:EOTB', a string (default ":EOTB") that delimits the text block when appearing on a line by itself; `:name', a string that names this text block, or `t' (default); `:coding', a symbol that specifies the coding to use when reading the text block, or `t' (default) which means use the current buffer's coding. [EXPERIMENTAL / DO NOT RELY ON THIS: Additionally, for control property `:data', the text-block spec must include `:seqr', a symbol naming a function defined in the `single' schema-schema.] Here is an example showing two `:display' specifications, both named, and the latter using `foo' as the end-of-text-block indicator: :display (:name "time first") At \time\ , we need to be at \place\ . :EOTB :display (:name "place first" :EOTB "foo") Let's try to be at \place at \time\ , for once! foo * Some properties specify a "string or regexp vector". This means the value is either a string, or a vector of either two or three elements, whose first element is a regular expression (string) and whose second element is an integer specifying the relevant submatch number (use 0 to mean that the text matched by the entire regexp is relevant). If the vector has three elements, the third element is a string used when writing. To maintain format integrity (to be able to read back what is written), this string should match the regexp specified in the first element. In other words: (let ((v [REGEXP SUBMATCH WRITE-STRING])) (string-match (aref v 0) (aref v 2))) should have a non-nil value. Be careful! (At this time, EDB does not check this relationship; you have to check it yourself. Omitting or specifying the wrong WRITE-STRING silently corrupts the data during write. This laxity ostensibly supports read-only interaction...) * Some properties specify a function that must "return a record initializer". This means the return value is either a plist of alternating field names (symbols) and values, or a list whose CAR is the keyword `:alist', followed by an alist associating field names and their values.  File: edb.info, Node: Control properties reference, Next: New control example, Prev: Kinds of control property values, Up: Specifying control 11.3 Control properties reference ================================= This section describes all the control properties recognized in the `single' schema-schema, grouped according to typical usage. *Note Kinds of control property values::, for information on common characteristics. 11.3.1 Minimal required ----------------------- Most control properties are optional; however, a minimal control requires `:display' and either `:fields' or `:tagged-setup'. `:display TEXT-BLOCK-SPEC' This control property is required. *Note Display specifications::. There may be more than one `:display' control property, in which case the respective TEXT-BLOCK-SPEC should include `:name STRING', and you should specify `:choose-display' to select one of the formats. `:fields VECTOR' Each VECTOR element is either a field name or a cons whose CAR is a field name and whose CDR is a type name (both symbols). Either `:fields' or `:tagged-setup' must be specified, but not both. *Note Record field types::. `:tagged-setup PLIST' PLIST must include `:fields (TAGGEDFIELDSPEC ...)', where each TAGGEDFIELDSPEC has the form `(FIELDSPEC TAG DESCRIPTION)'. FIELDSPEC can be either a field name, or a cons whose CAR is a field name and whose CDR is a type name. TAG and DESCRIPTION are both strings. *Note Tagged file layout::. Either `:fields' or `:tagged-setup' must be specified, but not both. *Note Record field types::. 11.3.2 File layout ------------------ Several control properties pertain to I/O, i.e., reading and writing to an external data source/sink. Note that some of these override others. *Note Database file layout::. `:read-record FUNCTION' FUNCTION is repeatedly called with no args to parse the accessible (narrowed) region of the data file, to return a record initializer for the data represented in that region. When called, point is at each region's point-min. If specified, control property `:field-separator' is ignored, since FUNCTION does all the parsing work. `:write-record FUNCTION' FUNCTION, whose arglist specifies field names, is called to insert into the current buffer at point the external representation of the current record's data. The arglist may also be nil, in which case all field values are dynamically bound to variables with the same names as the fields. `:record-separator-function FUNCTION' FUNCTION takes a buffer position, the end of the previous separator (that is, the start of the current record or field), and returns a pair of two buffer positions bracketing the next separator. That is, the returned values are the end of the current record or field and the beginning of the next one (or nil if there are no more). When FUNCTION is called, point is at the beginning of an item and the buffer is narrowed to the region being currently processed. If specified, `:record-separator' and `:record-terminator' are ignored. `:record-terminator STRING-OR-REGEXP-VECTOR' If specified, takes the place of (overrides) `:record-separator' and additionally specifies that STRING-OR-REGEXP-VECTOR appears after the last record, as well as between records. `:record-separator STRING-OR-REGEXP-VECTOR' The default is the string consisting of one newline (ASCII 0xA) character. `:field-separator STRING-OR-REGEXP-VECTOR' The default is the string consisting of one tab (ASCII 0x9) character. `:substitution-separators [FSEP RSEP]' A special case of `:substitutions' (below), FSEP and RSEP (both either a string or nil) specify what to write to disk in place of the regular field and record separators, respectively, in the case where those separators are found in the data itself. If unspecified, values are automatically chosen. (How?) `:substitutions VECTOR' Each element in VECTOR is a cons of two strings, specifying substitutions on the data to be made on read (beginning to end, s/car/cdr/) and write (end to beginning, s/cdr/car/) operations. Note: use `:substitution-separators' to disambiguate field and record separators instead of this control property. `:cruft [[BEFREC AFTREC] [BEFFLD AFTFLD]]' This is a catch-all for specifying irregular file formats. The value is a vector of two elements, each in turn a vector of two elements. Each of BEFREC (before record), AFTREC (after record), BEFFLD (before field) and AFTFLD (after field) is a string or regexp vector. `:data TEXT-BLOCK-SPEC' This is an EXPERIMENTAL control property that specifies that the data is inherent in the control (specifically, in the text block following this control property) instead of residing elsewhere. To "save" inherent data, EDB updates the text block and, if the control is associated with a file on disk, saves the control to disk. A control with inherent data can be useful for read-only and/or dynamically generated data sets. At present, inherent data usage is extremely stylized: * TEXT-BLOCK-SPEC must include `:seqr read-line', and the text block must consist of one vector, representing a record, per line. EDB does not validate the record for well-formedness. * TEXT-BLOCK-SPEC should include `:seqw write-line', if the data is to be saveable. (You may omit this if you plan to use the data in a read-only manner.) * If the control is not visiting a file, it must not be deleted for the lifetime of the data access. If the control is a file-visiting buffer, on the other hand, you can delete it without harm, once EDB is done processing it and has set up a data display buffer. In either case, you should take care to not modify the control while its data is under EDB's care, for that would probably confuse EDB when it tries to update the text block. Result: not only data corruption (bad), but control corruption (very bad), as well. 11.3.3 Display -------------- Some control properties affect what you see in an Emacs buffer. *Note How information is displayed::, and `:display' (above). `:choose-display FUNCTION' FUNCTION, whose arglist specifies field names, is called immediately prior to display a record in the data display buffer. It should return a string naming one of the display formats defined with `:display'. This function overrides that of `:before-display'. `:before-display FUNCTION' FUNCTION, whose arglist specifies field names, is called immediately prior to displaying a record in the data display buffer. This control property is ignored if `:choose-display' (above) is specified. `:report TEXT-BLOCK-SPEC' This specifies a report template. *Note Reports::. `:summary-format STRING' STRING is a concise (preferably one line) template for the summary buffer. *Note Database Summary mode::. 11.3.4 Miscellaneous -------------------- `:name STRING' STRING is used for informational purposes (messages and prompts). If unspecified, EDB assigns the default "Unnamed Database N", where N is some positive integer. `:first-change-function FUNCTION' FUNCTION is called the first time a field changes value (due to editing) with three args: the field name (a symbol), the old value, and the new value. `:every-change-function FUNCTION' FUNCTION is called every time a field changes value (due to editing) with three args: the field name (a symbol), the old value, and the new value. `:field-order VECTOR' VECTOR specifies the priority of significant fields for a sort operation (elements towards the beginning have precedence over those towards the end). Each element is either a field name or a cons whose CAR is a field name and whose CDR is a symbol: `ascending' or `descending', which specifies that the field is to be sorted in ascending or descending order, respectively; or a cons of TYPE and VALUE, where TYPE is a symbol (either `order-function' or `sort-function') and VALUE specifies the function. If unspecified, the default field order is taken to be the same as in `:fields', i.e., all fields significant and sorted in ascending order. *Note Sorting::. `:locals VECTOR' Each element of VECTOR is either a symbol, or a list of the form `(SYMBOL INIT-FORM)' -- like an entry in a `let'-bindings block. These define variables (mostly opaque to EDB) unique to the connection. The associated value is the value of evaluating INIT-FORM (if the element is a cons), otherwise nil. `:record-defaults FUNCTION' FUNCTION is called with no args when first adding a record, to return a record initializer.  File: edb.info, Node: New control example, Next: Ongoing migration, Prev: Control properties reference, Up: Specifying control 11.4 New control example ======================== This section describes a simple example database and the steps required to construct an appropriate control buffer to connect to it. First, we must decide how many fields the database shall contain, and their names and types. The names are Lisp symbols, and cannot be either `t' or `nil' for implementation reasons (those symbols cannot be used as variable names in Emacs Lisp). Let us make a name database with three string fields called `first', `middle', and `last' and one integer field called `age'. Next, we must decide how a record is to be displayed in an Emacs buffer. Let us try the following: Family: \last Given: \first Middle: \middle Age: \age The backslash followed by a field name indicates that the field's contents should be inserted there. For more information about specifying display formats, *Note How information is displayed::. Lastly, we need to compose a control buffer comprising a standard header, and the two pieces of information we've decided upon. So we type: * `C-x b my-names.edb ' * `M-x emacs-lisp-mode ' and insert the following (without the indentation): :EDB (single) ;;; -*- emacs-lisp -*- :fields [first middle last (age . integer)] :display t Family: \last Given: \first Middle: \middle Age: \age (Alternatively, we can insert the file `names.edb' from the EDB distribution's `examples' subdirectory, or simply visit it.) Now we can type `M-x edb-interact ' in this buffer, typing to specify this buffer as the control, and `my-names.data' (or any other non-existent filename) to specify the data. An "empty" record will be shown, ready to be filled in. *Note Database mode::. (Alternatively, we can specify the file `names.dat' from the EDB distribution's `examples' subdirectory, in which case the record for Harry S. Truman (age 88) will be shown.) When we write out the data, fields and records will be separated by tab and newline, respectively. These are the default delimiters. For more information about customizing EDB for your application, *note Customization::. Once we are happy with the control buffer, we can save it in a file for later use; we can then specify that file as the control for a subsequent `edb-interact' session.  File: edb.info, Node: Ongoing migration, Next: Changing control properties at runtime, Prev: New control example, Up: Specifying control 11.5 Ongoing migration ====================== Although most control can be declaratively specified, there are still some noticible holes (*note Control properties reference::), which we will endeavor to close as we proceed towards EDB 2.x. Notably, to extend the recognized types requires calling functions. *Note Specifying a record field type::, for record field types. *Note Defining new displaytypes::, for display types. Also, several variables (that are not set automatically when some control property is specified) are available for tweaking with `setq' and/or `add-hook': `db-before-read-hooks' `db-after-read-hooks' *Note Read hooks::.  File: edb.info, Node: Changing control properties at runtime, Next: Example control file from scratch, Prev: Ongoing migration, Up: Specifying control 11.6 Changing control properties at runtime =========================================== You can use `edb-get' and `edb-put' to access and modify, respectively, the value of certain control properties at runtime (and only at runtime, presently). -- Function: edb-get property &optional buffer Return the value associated with PROPERTY for the current buffer. Optional second arg BUFFER specifies another one to use as "current". -- Function: edb-put property newvalue &optional buffer Set PROPERTY to have NEWVALUE for the current buffer. Optional third arg BUFFER specifies another one to use as "current". The following table describes the available control properties. The default value is the one used when setting up the buffer. `:wraparound' (default: `delay') This controls motion between the first and last record (and vice versa), when moving sequentially between records. A value of `nil' means do not wrap around; stop at the first or last record and display a message to that effect. A value of `delay' (a symbol) means to stop at the border, displaying a message, but wrap on the next attempt to move, anyway. A value of `t' means to wrap without stopping, and without displaying a message. `:stay-in-edit-mode-p' (default: `t') A non-`nil' value means that when editing a record, moving to the next record stays in Edit mode.  File: edb.info, Node: Example control file from scratch, Prev: Changing control properties at runtime, Up: Specifying control 11.7 Example control file from scratch ====================================== This section describes three example databases of increasing complexity and their associated control files. The data is a set of "WWW Links". We start with just the URL and add fields/features as we go along. All files are available in the distribution's `examples' subdirectory. 11.7.1 WWW Links ---------------- "WWW Link" is a fancy way to say "URL". The simplest database is just a list of these in a file, one per line. For example: http://www.gnu.org/ http://www.gnu.org/software/ http://www.gnu.org/software/emacs/ http://www.gnuvola.org/ http://www.gnuvola.org/software/ http://www.gnuvola.org/software/edb/ It's easy to construct a minimal `www-links.edb' to grok this (note that (parenthesized) line numbers are for discussion, and should not appear in the actual working file): :EDB (single) (1) :name "WWW Links" (2) :fields [url] (3) :display t (4) \url (5) :EOTB (6) Line 1 is boilerplate and will be assumed henceforth. Line 2 names the database. Line 3 declares that each record is composed of one field, whose name is `url'. The field type's is taken (implicitly) as `string'. Lines 4 through 6 describe the per-record display. The `\url' in that text block means to display the field `url' at that position. That's it! Use `M-x edb-interact RET examples/www-links.edb RET RET' to try it out. (The last `RET' is to let EDB find the data file, which is `examples/www-links' by default. You can, of course, specify another data file to use instead of the default.) 11.7.2 WWW Links (Titled) ------------------------- In this subsection we extend the simple database introduced in the previous subsection to add a `title' field. Since the line-oriented (one record per line) approach is pleasant enough, the only design decision we have to make is how to separate the fields in each record, and their order. Although `TAB' (aka `^I' aka `C-i' aka "control i") is the traditional (and thus default) field separator, that might cause problems if that character were to appear in the title. We choose `^T' instead, since it is virtually guaranteed not to conflict, and "T" is a workable mnemonic for "title" (bonus!). As for the order of fields in the data file, let's keep the URL first since it is most important. (Although a title without a URL might be useful as a placeholder, our goal is to organize "links", which implies a certain connectedness requirement.) To effect this new design in a new data file, we can evaluate the form: (with-temp-file "www-links2" (insert-file-contents "www-links") (while (< (point) (point-max)) (end-of-line) (insert "\C-t") (forward-char 1))) Next we copy `www-links.edb' to `www-links2.edb' and make the following modifications: :name "WWW Links (Titled)" (1) :fields [url title] (2) :field-separator "\C-t" (3) :display t (4) \title (5) \url (6) :EOTB (7) Line 1 updates the title. Line 2 declares the ordering in the data file and names the second field `title', with type (implicitly) `string' as for `url'. Line 3 declares the field separator. Lines 4 through 7 describe the per-record display. Note that in the display we place the title first and on a line by itself. This has implications in the summary (*note Database Summary mode::), which defaults to the first line in the `:display' text block with a displayspec in it. With these changes, we can `edb-interact' with `www-links2.edb' and: type `e' once to enter edit mode; type in a title; use `M-n' and `M-p' to move to next/previous records, staying in the `title' field; type `C-x C-s' to save and `x' to exit. 11.7.3 WWW Links (Everything) ----------------------------- In this subsection, we further extend the database to include two fields: * date when the URL was last checked for reachability; * comments (notes, critiques, etc) For the date, we use a custom data type `suredate', defined as: (edb-define-recordfieldtype 'suredate 'date :actual->stored 'edb-t-timedate1:format-date-iso :stored->actual 'edb-t-timedate1:parse-date-string) Comments are just another string, but there is a catch: we would like to support multi-line comments, such as: This site is ok, but I wouldn't want to have to maintain it, for these reasons: - probably doesn't use EDB for its database - requires javascript, which w3m doesn't do The implication is that we can no longer use one record per line, as some records may contain the newline character in the `comments' field. So, let's choose formfeed (aka `^L' aka `C-l' aka "control l"). To effect this new design in a new data file, we can evaluate the form: (with-temp-file "www-links3" (insert-file-contents "www-links2") (while (< (point) (point-max)) (end-of-line) (insert "\C-t\C-t\C-l") (if (= (point) (point-max)) (delete-char -1) (forward-char 1)))) Next, we create `www-links3.edb', modifying the control property `:name', as usual, and adding `edb-define-recordfieldtype' as described above. The rest of the file looks like: :fields [url title (last-check . suredate) comments] :record-separator "\C-l" :field-separator "\C-t" :display t \title \url (\last-check,date-iso) Comments: \comments :EOTB :summary-format "\\last-check,width=11 \\title" Note that the `last-check' field is declared with type `suredate' in `:fields', is displayed with the `date-iso' format in the `:display' text block; and is explicitly included (with maximum width of 11 columns) in `:summary-format' (the double backslashes are required because the value is an Emacs Lisp string).  File: edb.info, Node: Record field types, Next: Database file layout, Prev: Specifying control, Up: Top 12 Record field types ********************* All the records of a database contain fields of the same types: the fifth field might always contain an invoice number, for instance, but the invoice number would vary from record to record. This chapter describes how to specify and use different record field types. The most important information about a record field is * display representation onscreen and in reports * EDB's internal representation * storage representation in data files * how to convert among these representations * how to sort items of that type This information is separated into a display specification and a record field specification. The display specification determines how a field's contents are displayed and parsed onscreen (say, in a data display buffer). The record field specification controls everything else about the record field; its information does not depend on the onscreen (or in-report) visual appearance of the field. The control specifies a displaytype for each display specification in the format file (that is, for each location in the data display buffer that will contain a representation of some record field), and specifies a record field type for each field in a database record, whether or not the field is ever displayed. (A particular field's contents may appear zero, one, or more times in a data display buffer; one displayspec structure is created for each occurrence.) Displaytypes and record field types are distinct; they supply complementary information. There is not even a one-to-one relation between them. A particular record field type may be displayed in any of a number of ways by using different displaytypes -- dates are such an example. On the other hand, record field types which are interpreted, sorted, and stored on disk differently, but which have the same internal representation -- say, as a string -- could all be displayed and edited using the same displaytype. This chapter discusses record field types, record field specifications, and lists the attributes upon which the other two are built. For more information about displaytypes, display specifications, and the displayspec structure, *note How information is displayed::. * Menu: * Specifying a record field type:: * Predefined record field types:: * Record field attributes::  File: edb.info, Node: Specifying a record field type, Next: Predefined record field types, Up: Record field types 12.1 Specifying a record field type =================================== The function `database-set-fieldnames-to-list' specifies the types (and names) of record fields. This function is called automatically when either of the control properties `:fields' or `:tagged-setup' is specified. -- Function: database-set-fieldnames-to-list database fspecs [dtype] Set DATABASE's field names and record field types according to FSPECS, canonicalizing and caching internally various things, but do nothing if the information has already been canonicalized. FSPECS is a list, each element of which can either be a single symbol, the field name, or a cons `(NAME . RECORDFIELDTPYE)'. Optional third arg DTYPE specifies the default recordfieldtype for single-symbol elements. If DTYPE is not given, use the value of `db-default-field-type' if bound, or `string' otherwise. Some notes on the deprecated variable `db-default-field-type': There has been some confusion over usage of this variable; the ideas of "default value" and of "buffer-local variable" do not mix well together, especially when the value in this case is the recordfieldtype of the field, a property of the field and not of its display mechanism or of any buffer. Thus, if you have old code that sets this variable, you should change it to pass that value as the third argument to `database-set-fieldnames-to-list'. A record field type gives information about one field of the database's records: the type of the contents, what sorting function to use, how to write it to disk and read it back, constraints on its value, etc. Each record field has a record field type. Usually one of the predefined types suffices, but not always. You can use `edb-define-recordfieldtype' to create and install a new record field type. (The `-from-recordfieldspec' in the function name is a historical artifact; before being extended, the function used to only accept a recordfieldspec as SOURCE.) -- Function: edb-define-recordfieldtype name source [override...] Define a recordfieldtype NAME (a symbol) with SOURCE. SOURCE may be a recordfieldspec, the name (a symbol) of a currently defined type, or `nil'. In all cases, a new recordfieldspec object is created and then modified by OVERRIDE, a sequence of alternating keywords and values, and finally added to a global list. Return NAME. *Note Predefined record field types::, for a list of symbols useful for the SOURCE argument. *Note Record field attributes::, for a list of keywords useful as part of the OVERRIDE argument. After specifying the field names and types, it is usually a good idea to specify some field-specific help, as well. This kind of help is kept separate from the `:help-info' of each recordfieldtype (*note Record field attributes::), since several different fields (requiring different help info) may specify the same recordfieldtype. -- Function: db-set-field-help database field1 help-info1 [...] Set field-specific help info for DATABASE from FIELD1 HELP-INFO1, .... FIELD1, FIELD2, ... should be field names (symbols) or field numbers, while HELP-INFO1, HELP-INFO2, ... should be either a string or a form to be evaluated that results in a string. *Note Getting help::. This should be called after the field names have been set up. Examples of record field type creation and installation can be found in the file `db-types.el', the source for most of the predefined types. Record field types should not be confused with display types; a display type is used to specify how a particular value is shown on the screen, but a record field type constrains the information actually contained in the record field.  File: edb.info, Node: Predefined record field types, Next: Record field attributes, Prev: Specifying a record field type, Up: Record field types 12.2 Predefined record field types ================================== The following record field types are predefined for your convenience; you can redefine them (they are not "privileged" in any way) or even add new record field types (*note Specifying a record field type::). If you find any of these typenames cumbersome, you can create your own aliases for them using `edb-define-displaytype' or `edb-define-recordfieldtype'. 12.2.1 Builtin -------------- These record field types are available as soon as EDB is loaded. `integer' Ordinary integers. `integer-or-nil' Integers or `nil', the empty value; by default, `nil' is treated as larger than any integer, so it comes last in an increasing-order sort. `number' Ordinary numbers. A number is either an integer or a floating-point number. `number-or-nil' Numbers or `nil', the empty value; by default, `nil' is treated as larger than any number, so it comes last in an increasing-order sort. `boolean' This displayspec corresponds to the yes-no displaytype. For the purposes of sorting, `t' is considered less than `nil', so it appears first in an increasing-order sort. `string' Ordinary strings. `one-line-string' Strings which may not contain newlines. `string-or-nil' Either a string or the value `nil', which is converted to the empty string. Sorting treats `nil' identically to the empty string. `nil-or-string' Identical to the string-or-nil record field type (except for the name). This exists so that display fields of type nil-or-string can conveniently default to this record field type. `one-line-string-or-nil' The obvious combination of the one-line-string and string-or-nil record field types. 12.2.2 From `edb-t-timedate1.el' -------------------------------- Loading `edb-t-timedate1.el' provides some record field types related to the times and dates. The "1" is for upward-compatibility with a future time/date library variation that will make use of Emacs' intrinsic time/date support. (`edb-t-timedate1.el' was written a while back, before such support was added to Emacs, and may become unavailable once again in the future. See its Commentary section for more info.) `date' A date which specifies zero or more of the year, month, and day. By default the date is sorted by year, then month, then day; an unspecified component is larger than any specified component. For example, `March 14, 1967' would appear before `January 1' if dates were sorted in increasing order. Dates are read from database files using a function that can parse nearly any string representation of a date and return a date object if it is passed one. Dates are written using a function which produces a string of the form `March 14, 1967'. `date-or-nil' A date, or nil. `date-efficient-storage' When the dates in a database file are known to have a particular format, using `edb-t-timedate1:parse-date-string' is unnecessarily inefficient. The date-efficient-storage record field type specifies that `edb-t-timedate1:storage-string->date', which can efficiently read dates written by `edb-t-timedate1:simple-format-date', be used instead. The time savings is noticeable on large databases. `time' A time.  File: edb.info, Node: Record field attributes, Prev: Predefined record field types, Up: Record field types 12.3 Record field attributes ============================ Record field attributes pertain to the content of a record field, but do not address how it is displayed on the screen or read from interactive input. For that, *Note How information is displayed::. Here is a table of valid attributes: `:type' A symbol such as `string' or `integer', the type of the data described by this collection of attributes. When no displaytype is explicitly specified in a display specification, then a displaytype with the same name as `:type' is used by default; this is the only use for this attribute. `:default-value' The default value for fields described by this collection of attributes; used when creating new records. `:common-form-function' A function which, called on the contents of a record field, returns them in canonical form. This can be used for determining non-trivial equality, when two nonidentical values should be considered equivalent. `:merge-function' A function which, called on the contents of two record fields, returns a combination of the two. It may be interactive. `:order-function' `:sort-function' The record field's ordering and sorting functions (*note Sorting functions::). Both ordering and sorting are possible if either attribute is specified. If both attributes are unspecified, then a dummy ordering or sorting function is used, so sorting on this field has no effect. Since the function is called and its result examined, this is more expensive than not sorting on the field in the first place. If it does not make sense to sort on a particular field, then it is best to keep that field out of the field priorities used for sorting (which is the `:field-order' control property, or is interactively specified through the database sort interface (*note Sorting::), or is specified as an argument to `database-sort'). Actually, the record field type does not include order-function or sort-function information directly; they are built upon the value of the `:field-order' control property. `:match-function' A function which takes a pattern and a field value and returns non-`nil' if they match. The function should also be able to take as its first argument a field value rather than a pattern. `:help-info' A string which is displayed by `db-field-help' when there is no field-specific help available. Field-specific help is usually preferable to this help, which only describes the type of the field's contents. `:actual->stored' A function which converts a field value into its on-disk representation (a string). `:stored->actual' A function which recovers a field value from its on-disk representation (a string). If this function returns a string, it should return something reasonable if supplied the empty string as its argument. (That can happen when an empty database is read.) `:constraint-function' A function which the value of this field must satisfy; that is, the function must return non-`nil' on it. The function may reject the value either by returning `nil' or by signalling an error; the latter permits the function to provide an informative message about the problem. Four arguments are supplied to `:constraint-function': the field value, the record, the record fieldnumber, and the database. This permits cross-field and cross-record constraints. The record argument may be `nil', in which case the function should return `t' if the value is acceptable for some conceivable record. This occurs, for instance, when values are read in a call to `db-field-query-replace'. The constraint function may be interactive; for instance, it may give you the opportunity to override the constraint.  File: edb.info, Node: Database file layout, Next: How information is displayed, Prev: Record field types, Up: Top 13 Database file layout *********************** This chapter discusses specifying how a database is read from a file (or saved back to it). Broadly stated, there are three possible file representations for a database: EDB's internal file layout, a delimited layout, or a nonregular layout. EDB's internal file layout is designed for fast reading and writing, but is not very human-readable. A delimited layout is one in which records (and fields within a record) are separated from one another in a predictable (though not necessarily invariant) way. A nonregular layout is any other kind of layout; you may specify arbitrary Emacs Lisp code to read and write such files. EDB also supports tagged file layout (a special case of nonregular file layout). If the database is to be stored in EDB internal file layout, a lot of this information is not needed except when the database is first created. The sections of this chapter each describe a file layout, except the last, which describes in detail the process of reading a database from disk. * Menu: * Data encoding:: * Internal file layout:: * Delimited file layout:: * Tagged file layout:: * Relational file layout:: * Nonregular file layout:: * Reading from disk::  File: edb.info, Node: Data encoding, Next: Internal file layout, Up: Database file layout 13.1 Data encoding ================== When connecting with `db-find-file', the format file can specify that coding system to be used for the data by setting `edb-data-coding'. This variable is not meaningful when control is specifed using control properties. -- Variable: edb-data-coding A symbol in the Local Variables section of the format file specifying the coding system Emacs should use when reading and writing the data file. This coding system may be different from the one used for the format file.  File: edb.info, Node: Internal file layout, Next: Delimited file layout, Prev: Data encoding, Up: Database file layout 13.2 Internal file layout ========================= EDB 1.x supports an "internal file layout", but EDB 2.x will not. This section details the layout, as well as how to migrate away from it (should you plan to move to EDB 2.x at some point in the future). * Menu: * Internal file layout details:: * edb-1int-to-single::  File: edb.info, Node: Internal file layout details, Next: edb-1int-to-single, Up: Internal file layout 13.2.1 Internal file layout details ----------------------------------- The first line of a database file in EDB's internal file layout looks something like ;; Database file written by EDB; format 0.7 followed by two Emacs Lisp forms: a vector (the database structure), and an alist of various miscellaneous attributes. The rest of the file is a sequence of vectors (the records of the database). Databases stored in this layout can be read and written very quickly (sometimes orders of magnitude faster than databases which EDB must parse when reading), and they never suffer from ambiguities between data and delimiting text, but they are not easy for people to read and understand. A human- or program-readable version of the database can be generated when it is needed, either by creating a report or by saving in some other file layout. This is a good option when all manipulation of a database will be done via EDB. Since this file layout is rather complicated, databases are often created in some other file layout and then converted to this one. To convert from another file layout to EDB's internal file layout, read in the database, use `db-toggle-internal-file-layout' to mark it for saving in that format, and then write or save the database (via `C-x C-w' or `C-x C-s'). -- Command: db-toggle-internal-file-layout Toggle whether the database will be saved in EDB's internal file layout. With a nonzero prefix argument, set it to use internal file layout. With a zero prefix argument, set it not to use internal file layout. After a database has been saved in internal file layout, then any forms in the auxiliary or format files that set database slots can be removed if desired; this is not necessary, however. Converting a database from EDB file layout to some other representation is similar, and certain variables and database values may need to be set (see the documentation for the layout you desire, elsewhere in this chapter). Making a report (*note Reports::) can also produce a different file layout for a database, with even more flexibility than the techniques described here.  File: edb.info, Node: edb-1int-to-single, Prev: Internal file layout details, Up: Internal file layout 13.2.2 edb-1int-to-single ------------------------- EDB 2.x will not support internal file layout. Instead, it will have (and EDB 1.26 and later already have some) support for control with "inherent data" via the `:data' control property (*note Control properties reference::). To ease migration, you can use `edb-1int-to-single' to do most of the tedious translation work, although you may need to help it a little. -- Command: edb-1int-to-single filename This command translates the contents of FILENAME to a "single" schema-schema. If the contents are not in EDB 1.x "internal file layout, format 0.7", it signals an error. Otherwise, it leaves the result of the translation in a newly created output buffer named `:EDB (single) from FILENAME'. To compute the control properties written in the output buffer, `edb-1int-to-single' uses various (nefarious) methods to parse and repurpose the contents of two files: the one named by FILENAME, as well well as the primary format file (if it can be determined -- see below). Additional format files and the auxiliary file, if any, are _not_ consulted. The local variables block in the primary format file can have either `eval: FORM' pseudo-variables or `VAR: VAL' specifications. If an `:eval' form looks like a function call for one of these functions: database-set-fieldnames-to-list --- "redundant" comment dbf-set-summary-format --- translate to :summary-format then `edb-1int-to-single' handles it specially (as indicated). An informative comment is also output to help keep track of things. If, on the other hand, the `eval:' form is not recognized, it is added to the output anyway, but commented out. Similarly, these variables (`VAR: VAL' in the local variables block) are handled specially: db-new-record-function dbf-first-change-function dbf-every-change-function dbf-before-display-record-function dbf-format-name-spec-alist edb-data-coding (i.e., commented out), and all others translated into `:locals'. Here are all the control properties written. Those in the first column are always written, while those in the second are conditionally written. :name :field-priorities :fields :summary-format :display :substitution-separators :data :substitutions :locals These short lists show that there are many control properties that `edb-1int-to-single' does not even attempt to infer. Indeed, even when it tries its best, the output buffer is likely to contain several `' tokens, indicating places where further attention (a nice way to say "manual tweaking") is required to complete the translation. Following is a complete table of possible `' occurances, with the reason for the `' and the suggested remedies. Note that suggestions involving editing the output buffer by hand are not compatible with those involving iteratively tweaking something in the input file or environment and re-invoking `edb-1int-to-single', since re-invocation clobbers hand-edits. Thus, a good strategy would be to do the upstream tweaking fixes first, saving the hand-editing fixes for last. `coding:' in the first line This occurs when the variable `coding-system-for-read' is `nil' during the call to `edb-1int-to-single'. This is a relatively serious situation, as recent versions of GNU Emacs may refuse to save the file altogether since `' does not name a valid coding system. One way to fix this is to replace the `' with the appropriate coding system for the control file (i.e., resorting to editing by hand). Another way is to call `universal-coding-system-argument' (normally bound to `C-x c') immediately prior to translation (via `M-x edb-1int-to-single'). Yet another way is to remove the `coding:;' completely, thus foisting the responsibility of specifying the file's coding system on another person (or mechanism) at another time. Note that you must remove the trailing semicolon as well. `:name' control property This occurs when the original name is `nil', which should never happen according to internal EDB constraints (but you never know). To fix, choose a suitable description for the data (a string) and replace the `' with it. `:display' control property This occurs when the primary format file cannot be determined. Normally, `edb-1int-to-single' looks for the filename of readable file first in the `:format-file' extra attribute, and then doing an "EDB 1.x-style" format-file search (*note Auxiliary files::). The easiest way to fix this is to make sure a the format file (or a symlink to it) is named in such a way that the search can find it. For example, if the internal file layout filename is `foo.bar.baz', make a symlink from the actual format file to `foo.bar.fmt'. primary format file's local variables block As mentioned above, an unrecognized `eval:' form is output anyway, but commented out. Included in the comment is a `'. Unfortunately, no general translation approach suggests itself since the form can be arbitrary Lisp code. If you are lucky, the form will be functionally redundant with one of the written control properties and you can simply delete it. The `VAR: VAL' variables listed above likewise have a `' included in their comment. For `edb-data-coding', you can copy its value to the first line. For `dbf-format-name-spec-alist', you need to manually create new a `:display' block for each format named [lame --ttn]. For the others, where the control property value is a function of some sort, you need to change the function to fit the expected calling convention of the associated control property [explain! --ttn].  File: edb.info, Node: Delimited file layout, Next: Tagged file layout, Prev: Internal file layout, Up: Database file layout 13.3 Delimited file layout ========================== EDB can conveniently read and write database files in which records are separated from one another by a record delimiter and, within each record, fields are separated by a field delimiter. When the delimiters are the newline and tab characters, respectively, the result is the standard "tab-separated text" layout, which is often used for transferring information from one program to another. The record and field delimiters need not be single characters; they can be arbitrary strings or even regular expressions. The latter is useful if the exact delimiter is not known ahead of time (for example, if records may be separated by one or more newlines). This regular expression mechanism can only be used when reading the database: when writing a database, all the record delimiters are identical, and so are all field delimiters. (Exception: you may specify an arbitrary record-writing function (*note Nonregular file layout::) and arbitrary functions for either reading records or for separating records or fields in delimited layout, but should use the simpler reading mechanisms whenever possible, for your own sake.) Using a delimited file layout has one important consequence: the delimiter strings may not appear in the data, lest those occurrences be misinterpreted as delimiters rather than as data. For solutions to this, *Note Resolving ambiguities::. * Menu: * How to specify delimited file layouts:: * Resolving ambiguities:: * Problems with end-of-file newlines::  File: edb.info, Node: How to specify delimited file layouts, Next: Resolving ambiguities, Up: Delimited file layout 13.3.1 How to specify delimited file layouts -------------------------------------------- If the data source can be represented as text in a buffer, and is amenable to separation using textual methods -- by recognizing a string, by matching against a regular expression, or by calling a stylized parsing function -- then it is said to be stored in a "delimited layout". Reading involves determining record and field boundaries followed by parsing the data fields. Writing involves inserting into an empty buffer representations of record and field boundaries interleaved with those of the data (and then saving the buffer to disk). The control properties (*note Control properties reference::), in order of importance for determining record boundaries when reading are: `:record-separator-function' followed by `:record-terminator' followed by `:record-separator'. For fields, the only applicable control property is `:field-separator'. To specify text at the beginning and/or end of the data (or at the beginning and/or end of each record) to ignore, use the `:cruft' control property. When writing, those control properties that specify a regexp vector (*note Kinds of control property values::), must specify the last element (a literal string), since it is not possible to reliably derive such a string from the regular expression and submatch information given in the first two elements of the vector. For instance, suppose a database has records with a variable number of fields separated by newlines, that records are also separated by newlines, and that the first field of each record has some special form different from all other fields (say, it is a number with a decimal part). The following code would permit separation of the records without writing a special function to do so and without including the decimal number in the separating text: :record-separator ["\\(\n\\)[0-9]+\\.[0-9]+" 1 "\n"] Be careful to use a correct value for separator strings. For instance, if your record separator is a form feed on a line by itself, you probably want to set `:record-separator' to `"\f\n"', or possibly `"\n\f\n"', rather than just `"\f"', lest the newlines be considered to be part of the records rather than part of the separator. 13.3.1.1 More examples ...................... For instance, to parse "[Mary, John,Jack, and Jill]" and to write it back out as "[Mary, John, Jack, Jill]", the following specification would suffice: :record-separator [", *\\(and +\\)?" 0 ", "] :cruft [["[" "]"] [nil nil]] [[[ This following example should go away when writing is converted from "all or nothing" to "selective update". The -string slots are used for writing; but what if you only have a regexp for the leading or trailing junk, but you want that restored exactly? You can set pre-first-string *after* the database file has been found. For instance, in db-before-read-hooks, use a function such as (defun btxdb:read-comments () (save-excursion (set-buffer db-buffer) (goto-char (point-min)) (when (search-forward "@" nil t) (setf (sepinfo-pre-first-string (database-record-sepinfo database)) (buffer-substring (point-min) (point)))))) or even put (setf (sepinfo-post-last-string (database-record-sepinfo database)) (with-current-buffer db-buffer (goto-char (point-min)) (re-search-forward "\n\C-l\n") (buffer-substring (match-beginning 0) (point-max)))) as is in your auxiliary file. ]]] If all records have five lines (say), you can use: :record-separator-function (db-make-n-line-sep-function 5) This is also useful when both the field separator and the record separator are the newline character. -- Function: db-make-n-line-sep-function n Return a function useful when all records have exactly N lines.  File: edb.info, Node: Resolving ambiguities, Next: Problems with end-of-file newlines, Prev: How to specify delimited file layouts, Up: Delimited file layout 13.3.2 Resolving ambiguities ---------------------------- Substitution is a mechanism for dealing with the problem of distinguishing field and record separators from the contents of database records. For instance, if the newline character (actually, a string consisting of only the newline character) is used as a record separator, and records may contain multiline text fields (or other fields whose storage representation contains a newline), then how would EDB know, when reading the database back in, which newlines are record separators and which are part of fields? There are several ways to avoid this ambiguity. * Disallow the use in record fields of the character or string causing the ambiguity. For instance, in the example above, you might change the record field type of all of the string fields to one-line-string. * Change the separator(s) to strings that do not appear in the storage representation of any field. For instance, Unix password files are stored in delimited file layout with a colon as the field delimiter (and colons are prohibited from appearing in the field text). :field-separator ":" Strings containing non-printing characters are another good bet, but this method relies on luck and the hope that the chosen separators will never appear in data. * Change the representation of the ambiguous string, when it appears in data; this guarantees that whenever the string does appear in a database file, it stands for a separator. This scheme is called substitution, because another string is substituted for the ambiguous one when it appears in data. This is similar to the previous workaround, which changed the separators rather than the data-bearing instances of the string. Ambiguities are still possible, if the substituted text happens to appear elsewhere in data. Specifying a substitution is described below. * The simplest solution is to use EDB's internal file layout (*note Internal file layout::). Ambiguities can only occur when the field data and the separators are both text to be interpreted by EDB. EDB's internal file layout uses Emacs Lisp's mechanisms (a built-in form of quoting) to ensure that what is read in is identical to what was written out. Substitution is the replacement of potentially ambiguous strings by other ones. For instance, when writing tab-separated text, each occurrence of the newline character in a field could be replaced by control-k when the database is written. Then, when the file is read in, every newline can be safely assumed to be a record separator. The final step is converting the control-k characters back into newlines. The problem with this approach is that if there were any control-k characters in the text, then when the database is read back in, they will be (incorrectly) converted to newlines. EDB warns when the database is being written out if this problem could occur; you may choose a different substitution or abort the database write operation. It is usually possible to find a substitution -- a character or sequence of characters that doesn't appear in the data. The `:substitutions' control property specifies a vector of string pairs: `(DATA . FILE)'. For example, to make control-k in the database file stand for newline in the data, include in the control: :substitutions [("\n" . "\C-k")]  File: edb.info, Node: Problems with end-of-file newlines, Prev: Resolving ambiguities, Up: Delimited file layout 13.3.3 Problems with end-of-file newlines ----------------------------------------- Suppose you want to get rid of every newline at the end of the database file, but you don't know how many there are. :cruft [[nil ["\n*\\'" 0 "\n"]] [nil nil]] does not work, because the post-last-record regexp is searched for backward from the end of the buffer, and (because of the way that `regexp-search-backward' is implemented) the backwards regexp match for `\n*' is always the empty string! The proper way to write this is :cruft [[nil ["[^\n]\\(\n*\\'\\)" 1 "\n"]] [nil nil]] *Note Control properties reference::.  File: edb.info, Node: Tagged file layout, Next: Relational file layout, Prev: Delimited file layout, Up: Database file layout 13.4 Tagged file layout ======================= Another popular file layout supported by EDB is that of field values preceded by the fieldname. For instance, a record might be represented in the file by Where:Here When: Now What: This! which indicates a record in which the `where', `when', and `here' fields have the specified values. Tagged files are a special case of files in nonregular layout; EDB supports them specially (*note Nonregular file layout::). To read a database file in tagged format, call the function `db-tagged-setup' in the database's format or auxiliary file. Its argument specifies the names of the fields and the tags that precede them in the database file. This function is called automatically when the `:tagged-setup' control property is specified. -- Function: db-tagged-setup fspecs [attrs...] Ready the database to read files in tagged format. Argument FSPECS is a list of tagged-field specifications, one for each field in a database record. Each tagged-field specification is a three-element list of the field name (a symbol), the tag used to identify it in the file (a string), and a brief help string. Instead of a symbol, the tagged-field name may be a cons of the field name and its type. To indicate that a field is never found in the input file (typically because it is computed on the fly), use nil for its tag. ATTRS is a sequence of alternating keywords and values specifying overriding attributes. Note: Do not call `database-set-fieldnames-to-list' if you call this function. Calling `db-tagged-setup' sets the database's field names, installs appropriate functions for reading and writing the database, and allows you to set attributes specific to a tagged database. For example, you can customize the behavior of the parsing and output functions with respect to what characters can appear in a tag, what the separator between tag and value looks like, and how continuation lines are handled. By default, records are separated by blank lines, tags are separated from field values by `:', white space around the separator is not significant on input, the separator is followed by one tab on output, and continuation lines start with whitespace. Some attributes permit arbitrary manipulations of records; for instance, if a database nearly conforms to the tagged file model, these can be used to customize the behavior of the existing tagged code. One way to do this is to set `:pre-parse-thunk' to a function that removes the field from the file representation before the record is parsed, and `:post-write-function' to a function to modify the automatically generated tagged file representation for that field. When using the tagged file layout, you should not (due to implementation restrictions) set variable `db-after-read-hooks' (*note Read hooks::). Instead, use the attribute `:index-function'. The following keywords are recognized in as part of the ATTRS argument to `db-tagged-setup'. Unless otherwise specified, the default value is `nil'. `:tag-chars' The characters that are allowed in field tags, in a string suitable for placing inside `[]' in a regular expression. Default value: `-_A-Za-z'. `:separator' The string that separates field names from values. Used only if `:separator-regexp' or `:separator-output' is `nil' (depending on whether the record is being read or written). Default value: `:'. `:separator-regexp' A regexp for the separator between field names and values when parsing. `:separator-output' The separator between field names and values on output. `:continuation' The string that marks (the beginning of) a continuation line. Used only if `:continuation-regexp' or `:continuation-output' is `nil' (depending on whether the record is being read or written). Default value: `\t'. `:continuation-regexp' A regexp for a continuation line in a value when parsing. Default value: `[ \t]+'. `:continuation-output' The fixed string to use (before) continuing values on output. `:pre-parse-thunk' On read, a function called with no arguments immediately prior to the tagged parsing. The buffer is narrowed to the region representing the current record. `:index-function' On read, a function called with one arg DATABASE, after all the records are parsed and converted from stored strings to actual objects. This is useful for doing accounting chores, such as indexing, on the entire set of records (*note Mapping over the database::). `:pre-write-function' On write, called with one arg RECORD before tagged writing. Point is where the record will be inserted in the buffer. `:post-write-function' On write, called with one arg RECORD after tagged writing. Point is immediately after the file representation of the record. `:default-field' A fieldname (symbol) for the field indicated by an illegal or empty tag. (For instance, you might set it to `comments'.) If `nil', those values are discarded.  File: edb.info, Node: Relational file layout, Next: Nonregular file layout, Prev: Tagged file layout, Up: Database file layout 13.5 Relational file layout =========================== [This node's documentation is poor primarily because, lacking examples of db-rdb.el usage to study, we make uninformed guesses. --ttn] The `db-rdb' library provides some functions for treating a database in a manner that allows correlation between fields, also known as relational capabilities, once the data is completely loaded into memory. On disk, the data must be stored in a variation of tagged file layout (*note Tagged file layout::). To access this kind of database, use `db-rdb-setup'. To correlate fields, use `db-rdb-correlate-field-defs'. Other (possibly useful) functions: `db-rdb-database-stored->actual', `db-rdb-list-rrfr', `db-rdb-list-wrfr', and `db-rdb-read-fields'. -- Function: db-rdb-setup rfspecs &optional lock-flag Ready the database to read files in RDB format. This creates database local variables and sets database slots. RFSPECS is a list of rdb-field specifications, one for each field in a database record. Optional, second argument LOCK-FLAG should be non-`nil' to lock the file for synchronized updates. The locking and unlocking is done with external programs `rdblock' and `rdbunlock', which must be available in the current PATH environment variable. Each field specification is a three-element list of the field name (a symbol), the tag used to identify it in the file (a string), and a brief help string. Instead of a symbol, the rdb-field name may be a two-element list of the field name its type. To indicate that a field is never found in the input file (typically because it is computed on the fly), use `nil' for its tag. -- Function: db-rdb-correlate-field-defs ifields efields Correlate the IFIELDS (internal fields) and EFIELDS (external fields) with each other and produce a field list suitable for `M-x db-rdb-setup'. IFIELDS is a list: `((HANDLE NAME HELP)...)', where HANDLE is either `(SYMBOL . TYPE)' or just SYMBOL. EFIELDS is a list: `((NAME WIDTH FORMAT HELP)...)', produced by the function `rdb-read-field-defs'. If TYPE is hidden, it is deduced from the corresponding FORMAT. Similarly, if the internal HELP is hidden, any external HELP is used. The internal definition always overrides the external, since it is more specific to the EDB implementation. The resulting list format is: `(((SYMBOL . TYPE) NAME HELP)...)'.  File: edb.info, Node: Nonregular file layout, Next: Reading from disk, Prev: Relational file layout, Up: Database file layout 13.6 Nonregular file layout =========================== Unlike most databases, EDB can work with data stored in any file layout whatever -- so long as you specify how the information is to be extracted. If the file layout is too complicated to be described by regular expressions describing the record and field separators and their context (*note Delimited file layout::), then you may write Emacs Lisp code which extracts the information from the database file. The great advantage of this mechanism is that it permits you to maintain your current files, in exactly their current file layouts, and to keep the same tools and habits you've accumulated, but also to manipulate them in a structured way with EDB. For instance, you might wish to maintain the database file in a file format easy for people to read all the time, rather than having to create a report for that purpose. Three pieces of information must be provided: how to find the extent of a file record, how to read a file record, and how to write a file record. The third may be omitted if the database is only being read in the custom file layout (and will be saved in some more tractable file format). If the second is provided (that is, the `:read-record' control property is specified), then the file will be assumed to be in a nonregular file layout and the function specified is used to read the database, no matter what other information is provided. Information about how to separate one record from another within the file is specified by the usual control properties (*note Control properties reference::). In many cases, even if the file layout of the data is nonregular, it is easiest to describe the record separator with a string or a regexp. For more details, *Note Delimited file layout::. You may also specify a `:record-separator-function' control property. The function should take one argument, the end of the previous record (`nil' the first time it's called), and return a pair whose car is the end of the current record and whose cdr is the start of the next record (`nil' if there is no next record in the file). The function specified for the `:read-record' control property is called with no arguments with the current buffer narrowed to a single file record (that is, narrowed to the representation of a single database record). It should parse the database's file layout and return a record initializer (*note Kinds of control property values::). The function specified for the `:write-record' control property takes zero or more args. If zero, the record's values are dynamically bound to variables whose names are the field names. If non-zero, the function's arglist specifies those fields whose values are to be passed in. (This latter case is useful if some fields are computed.) The function should insert the file representation of that record in the current buffer. If `:write-record' is not specified (and the data is not in internal layout format), then the field separator and record separator information, if present, is used to write the record (*note Delimited file layout::). This permits the use of a simple, delimited output file layout with a more flexible input file layout. Tagged format is a special case of nonregular file layout for which EDB provides support (*note Tagged file layout::). Another example is given below. * Menu: * Nonregular database example::  File: edb.info, Node: Nonregular database example, Up: Nonregular file layout 13.6.1 Example of database in nonregular file layout ---------------------------------------------------- Here is a simple example of a database in a nonregular file layout; this does not mean that the file representation of each record is vastly different from the others (it may be, but is not in this instance), but that there is no regular rule for extracting field values from the record. Suppose we had a database with fields `place', `time', and `purpose', whose database file was: Dentist's Office at Never! for Root canal Home at Midnight for Sleep Other places at Other times for Other things In order to read and write this database, place the following code in the auxiliary file (*note Reading from disk::): (setf (database-read-record-from-region database) 'arb-demo-rrfr (database-write-region-from-record database) 'arb-demo-wrfr) (defun arb-demo-rrfr () (unless (re-search-forward "\\(.*\\)\s-+at\\s-+\\(.*\\)\s-+for\\s-+\\(.*\\)") (error "This didn't look right to me.")) (list 'place (match-string 1) 'time (match-string 2) 'purpose (match-string 3))) (defun arb-demo-wrfr (record) (insert (db-record-field record 'place) " at " (db-record-field record 'time) " for " (db-record-field record 'purpose))) The auxiliary file would also specify the database's field names: (database-set-fieldnames-to-list database '(place time purpose)) as well as possibly other information such as the summary format or the name of the default format file. See the example database auxiliary file `arb-demo.dba' for a concrete example of this. All this Emacs Lisp code may be placed in the local variables section of the format file instead of in the auxiliary file, if desired. For more information about the local variables section of a file, *Note File Variables: (emacs)File Variables. This particular example is simple enough that a special function for reading isn't strictly necessary. Reading can be done under the control of regular expressions; for instance, each field separator would be `"\\s-+\\(at\\|for\\)\\s-+"'. See the example database auxiliary file `arb-demo-regexp.dba' for a concrete example of this. You would still need to specify a special record-writing function. Here is another example, which has no field separators; in the data file, the fields abut one another. While it, too, could be read and written under the control of regular expressions, the use of functions is a bit clearer. The data file is: Einsteinbirthday03141879 Botswanaindepend09301966 The auxiliary file contains the following: (setf (database-print-name database) "Historic Dates") (database-set-fieldnames-to-list database '(name occasion month day year)) (setf (sepinfo-sep-string (database-record-sepinfo database)) "\n") (setf (database-read-record-from-region database) 'sized-field-rrfr (database-write-region-from-record database) 'sized-field-wrfr) (defvar sized-field-alist '((name . 8) (occasion . 8) (month . 2) (day . 2) (year . 4))) (defun sized-field-rrfr () (let ((field-begin (point)) pl) (dolist (this-size-cons sized-field-alist) (forward-char (cdr this-size-cons)) (push (buffer-substring field-begin (point)) pl) (push (car this-size-cons) pl) (setq field-begin (point))) (unless (eobp) (error "Found extra characters in this record.")) pl)) (defun sized-field-wrfr (record) (mapcar (lambda (this-size-cons) (let ((v (db-record-field record (car this-size-cons)))) (if (not (= (length v) (cdr this-size-cons))) (error "Field %s value %S has length %d (should be %d)." (car this-size-cons) v (length v) (cdr this-size-cons))) (insert v))) sized-field-alist)) This example is actually a bit too simple. Some of the fields could be made non-strings, field constraints should keep the fields the right length, and `sized-field-alist' should be a database-local variable.  File: edb.info, Node: Reading from disk, Prev: Nonregular file layout, Up: Database file layout 13.7 What happens when a database is read in from disk ====================================================== In brief, the following happens after you execute `db-find-file': 1. If the database is already read in and its buffer has not been killed, the buffer is simply selected. No other work is done. 2. Otherwise, the database file is inserted in a special buffer of its own. If the database is in EDB internal file layout (that is, if an identifying header is found), it is read in immediately. Otherwise, a new, empty database is created. In either case the dynamic variable `database' is bound; this makes it possible to refer to the database in the auxiliary and format files (even before it has been read in, if it is not in EDB internal file layout). 3. The format file is found (*note Auxiliary files::), and the data display buffer is created. 4. Perform the rest of the work necessary for setting up the data display buffer (everything up to the running of `db-before-read-hooks'). The first action is to insert the format file's contents into the data display buffer. 5. The auxiliary file, if any, is loaded. This happens in the data display buffer, and the dynamic variable `database' is bound to the current database. For more information about how the auxiliary file is found and what it can do, *Note Auxiliary files::. The auxiliary file is not read every time the previous step occurs, only when a database's primary display format is read. (The primary display format is the one initially selected when a database is first read in.) 6. The local variables section, if any, of the format file is executed; this may set variables and execute Emacs Lisp code, exactly analogously to the auxiliary file. EDB ignores the value of `inhibit-local-variables' when evaluating this code. This section is then deleted from the working copy of the file, so that it does not appear in the data display buffer when you view database records. *Note File Variables: (emacs)File Variables, for more information about the local variables section of a file. 7. Database information is propagated; for instance, the names of the database fields are known by now, and various other internal state is initialized depending on this information, if necessary. 8. The format file is parsed, and literal text and formatting directives are distinguished from one another. This completes the preparation of the data display buffer. 9. Run `db-before-read-hooks'. 10. If the database had already been read because it was stored in internal file layout, it is massaged a bit to get it into its final form. Otherwise, the database is finally read; the values of the `:record-FOO' and `:field-separator' control properties determine whether the layout is delimited or nonregular and direct the parsing. The `:substitutions' control property directs replacement of characters that could not be written into the file, and the `stored->actual' slot of each record field type completes the translation to the data's internal format from its file layout. 11. Run `db-after-read-hooks'. 12. The database has now been read and is in its final form. The first record of the database is displayed in the data display buffer, which is then placed in view mode and selected (made visible).  File: edb.info, Node: How information is displayed, Next: Customization, Prev: Database file layout, Up: Top 14 How information is displayed ******************************* The display of information, both on the screen (whether in the data display buffer, the summary buffer, or elsewhere) and in other output (such as reports), is controlled by formatting commands. We will discuss a data display buffer by way of example; the formatting specifications are the same for summary buffers and reports as well. Display types should not be confused with record field types; a display type is used to specify how a particular value is shown on the screen, but a record field type constrains the information actually contained in the record field. This chapter does not discuss record field specifications, which specify everything about a record field type except how it is displayed and parsed in output intended for humans to read. For more information about that, and about the distinction between record field types and displaytypes (the latter of which is described in this chapter), *note Record field types::. A display format gives all of the information necessary to create a data display buffer; it consists of literal text that is displayed as is (without possibility of editing) and of "display specification"s that instruct EDB how to display a particular field's contents. The display specifications do not appear in the data display buffer; they are replaced by fields' values, which may or may not be editable. An example of a display specification is `\name,width=16', which indicates that the `name' field of the database should be displayed (after being padded or truncated to exactly 16 characters). When a format is first specified, it is parsed and the formatting information specified in the display specification strings is used to create a displayspec structure. * Menu: * Display specifications:: * Predefined displaytypes:: * Enumeration displaytypes:: * Defining new displaytypes:: * Display specification optional parameters::  File: edb.info, Node: Display specifications, Next: Predefined displaytypes, Up: How information is displayed 14.1 Display specifications =========================== A "display specification" describes how a particular database record field appears in the data display buffer. An display specification consists of a backslash followed by a field name, plus perhaps some optional type and formatting information, plus optionally a backslash followed by a space. The items of extra formatting information must be separated from the field name and from each other by commas. No spaces or tabs may occur in a display specification. To specify a backslash which does not begin a display specification, but should appear in the data display buffer verbatim, precede it by another backslash. Here is a (quite complicated) example display format: \name,one-line-string,actual->display=upcase\ , \occupation' Pay: \\\salary,min-width=4: too much! Address: \address,indent is home sweet home This display format is valid if the database contains fields called `name', `occupation', `salary', and `address'; any other fields are not displayed. Some typical records would be displayed like this: JOHN DOE, butcher Pay: \ 22: too much! Address: 123 Main St. Anyplace, USA is home sweet home JANE ROE, baker Pay: \4444444: too much! Address: 675 Massachusetts Avenue is home sweet home The optional information includes the type of this display field and formatting directives for it; if the type is present, then it must come first among the displayspec's optional specifications. Each optional parameter is preceded by a comma to separate it from the preceding one (or from the fieldname, for the first optional parameter). The optional information is typically of the form `SLOTNAME=VALUE', which sets the specified slot to the given value, or `SLOTSETTER', which sets some slot to a particular value. Explicitly specified formatting information overrides any defaults. For a list of slotnames and slotsetters, *note Display specification optional parameters::. The display type can be specified by writing the typename (such as `string' or `integer') as the first optional parameter. The display type specifies default values for the display specification (actually for the displayspec structure, which is derived from the display specification). It is rarely necessary even to specify the displaytype -- most display specifications consist of simply a backslash and a fieldname -- since if the displaytype is omitted then a displaytype with the same name as the record field type (actually the `:type' attribute of the record field type) is used. This works because typically displaytypes and recordfieldtypes with the same names and complementary definitions are declared at the same time. The displaytype must be compatible with the record field type; it is an error to specify a displaytype of `integer' when the data is actually a string. `database-set-fieldnames-to-list' to specify recordfieldtypes; *note Specifying a record field type::.  File: edb.info, Node: Predefined displaytypes, Next: Enumeration displaytypes, Prev: Display specifications, Up: How information is displayed 14.2 Predefined displaytypes ============================ The following displaytypes are predefined. Most of them correspond directly with the same-named record field type; *Note Predefined record field types::. You can also define displaytypes of your own; *Note Defining new displaytypes::. 14.2.1 Builtin -------------- These displaytypes are available as soon as EDB is loaded. `integer' Ordinary integers. `integer-or-nil' Integers or `nil', the empty value; `nil' is formatted as the empty string. `number' Ordinary numbers. A number is an integer or a floating-point number. `number-or-nil' Numbers or `nil', the empty value; `nil' is formatted as the empty string. `yes-no' This displayspec corresponds to the `boolean' recordfieldtype. The field is three characters long and contains "Yes" or "No ". `string' Ordinary strings. By default there is no maximum or minimum width or height, and subsequent lines are indented relative to the first character of the first line. `one-line-string' Strings which may not contain newlines. `string-or-nil' Either a string or the value `nil', which is displayed as the empty string. `nil-or-string' Either a string or the value `nil'. When you enter the empty string as the field value, or when a new record is created, the value `nil' is used in preference to the empty string. `one-line-string-or-nil' Either the value `nil' or a string which may not contain newlines. 14.2.2 From `edb-t-timedate1.el' -------------------------------- Loading `edb-t-timedate1.el' provides additional displaytypes, and related functions. `date' A date which specifies zero or more of the year, month, and day; any or all of these components may be hidden. The date is created by the constructor `edb-t-timedate1:make-date' and a date's components are retrieved using the selectors `edb-t-timedate1:date-year', `edb-t-timedate1:date-month', and `edb-t-timedate1:date-day'. A date is formatted by `edb-t-timedate1:format-date' and parsed by `edb-t-timedate1:parse-date-string'. -- Function: edb-t-timedate1:make-date year month day Make an EDB date object representing YEAR, MONTH, and day DAY (all integers). -- Function: edb-t-timedate1:parse-date-string s Parse string S, and return an EDB 1.x date object. Signal error if the parse is invalid. If S contains only whitespace, return a null date object. If S is `nil', use the result of calling `edb-t-timedate1:parse-date-default-function' instead. -- Function: edb-t-timedate1:format-date fmtstr &optional date Using FMTSTR, format the DATE, which defaults to the current date if `nil'. FMTSTR can contain the following symbol strings, which are substituted by their corresponding value from the date; other characters are inserted as-is. `%d' day of month -- 1 to 31 (one or two digits) `%dd' day of month -- 01 to 31 (always two digits) `%m' month of year - 1 to 12 (one or two digits) `%mm' month of year - 01 to 12 (always two digits) `%mon' month name (abbreviated) - Jun `%month' full month name - June `%yy' last 2 digits of year - 00 to 99 `%year' year as 4 digits -- 0000 to 9999 `%jday' Julian day of year -- 1 to 366 `%wday' day of week -- 0 to 6 (Sunday = 0) `%day' day of week name -- "Sun" to "Sat" `%weekday' full day of week name -- "Sunday" to "Saturday" See the variables `edb-t-timedate1:format-date-sub-syms-alist' and `edb-t-timedate1:format-date-sub-syms-regexp'. A special case: if an element of DATE is `nil', its field is hidden. A DATE object of all `nil's is thus formatted as the empty string. -- Function: edb-t-timedate1:simple-format-date date Format the DATE using a default format, defined by the variable `edb-t-timedate1:simple-format-date-default'. If DATE is `nil', use the value of `edb-t-timedate1:parse-date-default-function'. `date-mmddyy "/"' `date-yymmdd "" (empty string)' `date-ddmmyy "."' `date-ddmmmyy " " (space)' `date-yyyymmdd "/"' These are based on the `date' displaytype, and are meant to be used in a display spec, such as: \datefield,date-mmddyy The formatting for each `date-FOO' is done by a function `edb-t-timedate1:format-date-FOO', for example `date-mmddyy' and `edb-t-timedate1:format-date-mmddyy'. These functions all accept an optional second arg SEPARATOR that can be used to override the default (shown after the name above). `date-iso' `date-europe' `date-full' `date-all' `date-unix' `date-dec' More `date'-based displaytypes, similar to the previous group, except that the associated functions take only one arg (the date). `time' A time which specifies zero or more of the hour, minute, and second. The time is formatted by `edb-t-timedate1:format-time' and parsed by `edb-t-timedate1:parse-time-string'. The time is created by the constructor `edb-t-timedate1:make-time' and a time's components are retrieved using the selectors `edb-t-timedate1:time-hours', `edb-t-timedate1:time-mins', and `edb-t-timedate1:time-secs'. A time is formatted by a `edb-t-timedate1:format-time-SPEC' function and parsed by `edb-t-timedate1:parse-time-string'. -- Function: edb-t-timedate1:make-time hours mins secs Make an EDB time object representing HOURS, MINS, and day SECS (all integers). -- Function: edb-t-timedate1:parse-time-string s Parse the first occurrence of `hh:mm:ss' in string S; return a time object. If ":ss" is hidden in S, the seconds default to zero. If S contains only whitespace, return an empty time object. If S is `nil', use instead the result of `edb-t-timedate1:parse-time-default-function'. -- Function: edb-t-timedate1:format-time-12 time -- Function: edb-t-timedate1:format-time-24 time -- Function: edb-t-timedate1:format-time-hhmm time -- Function: edb-t-timedate1:format-time-12-hhmm time -- Function: edb-t-timedate1:format-time-24-hhmm time Format TIME in various ways.  File: edb.info, Node: Enumeration displaytypes, Next: Defining new displaytypes, Prev: Predefined displaytypes, Up: How information is displayed 14.3 Enumeration types ====================== An enumeration displaytype is used for fields whose values are one of a fixed set of alternatives. Each alternative consists of an entire string entered in the minibuffer with completion. (The string may consist of only a single character, but you must still type after entering the string. Also, completes a partly-entered choice, and lists the remaining possibilities. *Note Completion: (emacs)Completion, for more about completion.) The internal representation of the data -- its recordtype -- need have nothing to do with the way that the alternatives are specified. This section describes the enumeration displaytype, which is nicknamed "enum". The internal, input, display, and file storage representations of the value may all be different. This displaytype is created by calling the following function, which also creates a corresponding recordfieldtype. -- Function: edb-define-enumtype typename alternatives [optstring] Make TYPENAME (a symbol or string) an enumerated type. Both a displaytype and a recordfieldtype are created. ALTERNATIVES is a list. Each alternative is a list of up to four components: the internal representation, any constant Lisp object, often a string; the input representation input interactively to specify this alternative, a string or list of strings (for multiple input representations); the display representation, a string; and the file storage representation, a string. If the input representation is omitted and the internal representation is a string, that string is used. If the display representation is omitted, it defaults to the first input representation. The display representation is automatically also a valid input representation. If the file storage representation is omitted, it defaults to the display representation. If all the other components are omitted, the internal representation string may be used in place of a one-element list containing just it. Optional argument OPTSTRING is a displayspec option string. When a record field's type is an enum type, it can be assumed that the value in the record field is one of the valid representations. (Similarly, when a field's type is string, EDB can assume that the field content is actually a string.) This means that the empty string, `nil', and other special values must be specifically mentioned when the enumeration type is defined. Here is a way to define an enumeration type which is either a day of the week or the empty string: (edb-define-enumtype 'workday '("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "")) If it is possible for the field value to be `nil' (but not the empty string) after reading the database, and `nil' should be displayed as `Unknown' (and that string parsed into a value of `nil'), the following definition suffices: (edb-define-enumtype 'workday '("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" (nil "Unknown")))  File: edb.info, Node: Defining new displaytypes, Next: Display specification optional parameters, Prev: Enumeration displaytypes, Up: How information is displayed 14.4 Defining new displaytypes ============================== When you are about to type a complicated display specification -- or a simple one more than once -- consider defining and using a displaytype instead. Displaytypes are more concise (and so less cumbersome and less error-prone), easier to change (since a change to the displaytype can affect every display specification that uses it), and clearer (since a descriptive typename makes immediately clear what the intention is). Furthermore, displaytypes can be built up incrementally, with each one making a few changes to those from which it inherits defaults. Use `edb-define-displaytype' to define a new displaytype. -- Function: edb-define-displaytype name source [override...] Define a displaytype NAME (a symbol) with SOURCE. SOURCE may be a displayspec, the name (a symbol) of a currently defined type, a string representing the optional parameters part of a displayspec, or nil. In all cases, a new displayspec object is created and then modified by OVERRIDE, a sequence of alternating keywords and values, and finally added to a global list. Return NAME.  File: edb.info, Node: Display specification optional parameters, Prev: Defining new displaytypes, Up: How information is displayed 14.5 Display specification optional parameters ============================================== This section describes the display specification optional parameters, which correspond exactly to slots of the displayspec, EDB's internal representation of the display specification. Optional display specification parameters are separated only by commas; display specifications never contain whitespace. These parameters are of two forms: slotsetters, which are a single word and set a slot to a particular value; and slot assigners, which are of the form `SLOTNAME=VALUE' and set the slot to the value. Unless otherwise specified, each slot can be set by a slot assigner whose name is the same as that of the slot. An example of a display specification containing two optional parameters, one a slot assigner and one a slotsetter, is `\name,width=16,unreachable'. Display specification fields are processed in order, so only the last instance of a particular parameter has any effect. Any explicitly specified parameter overrides defaults, values inferred from the type, or previously specified parameters. If you find yourself repeatedly writing similar display specifications, or large, bulky display specifications, consider defining a new type to do some or all of the work for you; *Note Defining new displaytypes::. `record-index' This integer is the field index in a database record of the value formatted by this displayspec. This is set by looking up the fieldname part of the displayspec. `indent' This boolean value determines whether the second and subsequent lines should align with the beginning of the first one or should be flush left, in column 0. It is set and unset with the `indent' and `noindent' slotsetters. The first of the following displays has indent set, and the second does not: Name: John Doe Address: 123 Main St. Anyplace, USA Name: John Doe Address: 123 Main St. Anyplace, USA This causes alignment of the first character of subsequent lines with the first character of the first line; it does not do anything clever with whitespace in the field value, nor does it align different lines differently. `min-width' `max-width' These integers are the minimum and maximum widths which the display may occupy. If the formatted value is too short, the function in the `padding-action' slot is called to lengthen and/or justify it. If the formatted value is too long, the function in the `truncation-display-action' slot is called to shorten it; if that slot is empty, the field is simply truncated. The `width' slot assigner sets both the `min-width' and `max-width' displayspec slots. The `min-length', `max-length', and `length' slot specifiers are synonyms for the `min-width', `max-width', and `width' slot specifiers. `min-height' `max-height' These are analogous to `min-width' and `max-width', but for the number of lines occupied by the formatted value (actually, the number of newlines in the string, plus one). There is a `height' slot assigner which sets them both. `truncation-display-action' This function helps reduce the size of the formatted value when it is too large to fit in the specified displayspec size. It defaults to simply truncating the formatted field to the maximum permissible size. It may also be set with the `trunc-display' slot assigner. At present, this function is only called if the formatted value is too wide; there is no analogous function called when it is too tall. `padding-action' This function determines how a field that is too small for the displayspec (that is, the printed representation contains fewer characters than specified in the `min-width' slot) should be expanded to fit. The padding function takes three arguments: the minimum length, the unpadded display representation, and the length of that representation. The `padding-action' slot may also be set to a cons of a padding character and a padding direction: `nil' for left-justification (padding on the right), and non-`nil' for right-justification. (You cannot set the `padding-action' displayspec slot to a cons by using a display specification, since display specifications may not contain whitespace, so the easiest way to right-justify a single field is to use the `right-justify' slotsetter.) The default, which can also be obtained just by setting the slot to `nil', is to pad on the right with space characters. `actual->display' `display->actual' These functions convert between the data's internal representation and its displayed representation (a string). Other functions (such as those in the `truncation-display-action' and `padding-action' slots) may then be called on the result returned by the `actual->display' function. These slots may be set with the `a->d' and `d->a' slot assigners. The `display->actual' function takes either one argument or four arguments: either just the field text or the field text, the previous field value, the record being operated upon, and the record fieldnumber of the field in question. EDB ascertains at runtime how many arguments the function should be applied to. The old field value is passed in case it contains hidden (undisplayed) attributes that need to be preserved across changes. The other two arguments permit a particular `display->actual' function to be used for more than one field of a record, allow the field text parse to depend on other record field values, and provide for other complicated needs. Most `display->actual' functions can be specified to take a single argument. The `actual->display' function takes either one argument or three arguments: either just the field value or the field value, the record, and the record fieldnumber. EDB ascertains at runtime how many arguments the function should be applied to. The reasons the additional arguments may be specified are similar to those outlined above (for instance, to permit the displayed representation of a field to depend on other information in the record); most `actual->display' functions take just one argument -- for instance, `upcase' is a valid `actual->display' function. `match-actual->display' `match-display->actual' These functions are like `actual->display' and `display->actual', but are only invoked when reading a displaying a search specification. If they are not specified (as is usually the case), then the ordinary (`match-'-less) versions are used for search specifications as well. These slots should be set to symbols, not to functions proper; that is, to specify that function `foo' should be used, set the slot to `'foo', not to `(function foo)'. `truncation-editing-action' This function specifies what to do when a field being edited is too large for the specified displayspec size; this action may be different from that taken when simply displaying the offending value. It may also be set with the `trunc-edit' slot assigner. `reachablep' A Boolean value determining whether movement commands should skip this display field. The `reachable' and `unreachable' slotsetters are used to assign a value to this slot.  File: edb.info, Node: Customization, Next: Database representation, Prev: How information is displayed, Up: Top 15 Customization **************** * Menu: * Auxiliary files:: * Hooks and customization functions:: * Global variables::  File: edb.info, Node: Auxiliary files, Next: Hooks and customization functions, Up: Customization 15.1 Auxiliary and format files =============================== When using control properties, this section has no meaning (you can skip it), since aux file functionality is handled by the free-standing Lisp in the control file. EDB 2.x will not have handling for format and auxiliary information in separate files outside that provided by the `:display' control property and `load'. You can provide code to be executed when the database is read in (*note Reading from disk::). The optional auxiliary file usually contains the code specific to a particular database, but the format file, which specifies the on-screen arrangement of fields of a record, can also contain such code. Since the auxiliary file is read after the format file has been found but before it has been parsed, neither file can specify the other. The format file can, however, load arbitrary files, which is nearly as good as being able to specify an auxiliary file. EDB looks for a file with the same name as the database file, but ending with one of the suffixes in `db-aux-file-suffixes'. -- Variable: db-aux-file-suffixes List of auxiliary file suffixes; the basename is that of the database file. The suffixes are tried in order; the default is `(".dba" ".aux" "a")'. The `.' that may precede the extension must be specified explicitly. -- Variable: db-aux-file-path List of directories (strings) to search, in order, for auxiliary files not found in the directory with their associated databases. The auxiliary file is evaluated in the data display buffer and so can set variables local to that buffer, such as hooks (*note Hooks and customization functions::). The database itself can be manipulated via the dynamic variable `database'. For instance, auxiliary files often set the name (a string) of their associated databases. Code in an auxiliary file should be specific to the particular database; more general code is best placed in a separate file which is `load'ed (or, better, `require'd) by the auxiliary file. For instance, if you want to permit EDB to manipulate files of type Foo, you should put all Emacs Lisp code that applies to every Foo file in one file (`db-foo.el', say), and then put `(require 'db-foo)' in the auxiliary file associated with a particular Foo file. (Alternately, you may autoload a function that will be called in the auxiliary file; function `db-tagged-setup' is autoloaded from `db-tagged.el' in this manner.) Either technique keeps auxiliary files simple and small and makes Foo-specific code easier to debug, byte-compile, and load only once per session. These advantages easily outweigh the introduction of an extra file. Since the format file has not yet been interpreted, the auxiliary file could even change the contents of the buffer (and so the apparent contents of the format file); such extreme trickiness is only called for in special circumstances. The format file can contain Emacs Lisp code in its local variables section; that code can do anything that code in the auxiliary file can do. EDB tries to find one based on the database file name and the suffixes in `db-format-file-suffixes'; if that doesn't work, you are prompted for a display format to use. -- Variable: db-format-file-suffixes List of format file suffixes; the basename is that of the database file. The suffixes are tried in order; the default is `(".dbf" ".fmt" "f")'. The `.' that may precede the extension must be specified explicitly. -- Variable: db-format-file-path List of directories (strings) to search, in order, for format files not found in the directory with their associated databases. Code in the format file is useful for customizations specific to a particular format (such as setting variables which are local to the data display buffer); they can also be used for database-specific customizations if the file will always be the primary (first-selected) format for the database.  File: edb.info, Node: Hooks and customization functions, Next: Global variables, Prev: Auxiliary files, Up: Customization 15.2 Hooks and customization functions ====================================== The following sections describe EDB's hooks and customization functions. *Note Hooks: (emacs)Hooks. Many of these hooks are change hooks, which permit a function (or functions) to be run whenever a value changes. These change hooks may be divided into two basic types: format change hooks and record field type change hooks (however, the latter is not yet implemented and probably will never be). The former are associated with a particular display format and are invoked when the value in a particular field, or in any field, changes. The latter (which are not yet implemented) are associated with a record field type and are invoked whenever a database record slot of a particular type is changed. * Menu: * Read hooks:: * Database mode hooks:: * Record display hooks:: * Edit mode hooks:: * Display format change hooks::  File: edb.info, Node: Read hooks, Next: Database mode hooks, Up: Hooks and customization functions 15.2.1 Read hooks ----------------- The following two hooks are useful for causing database values seen by EDB to be different than those in the database file. The first can be used to modify the database file before it is read in; the second can be used to modify the database after it has been read in but before EDB displays it. -- Variable: db-before-read-hooks Normal hook run immediately before a database is first read but after all local variables are set. The hooks are run in the data display buffer with variable `database' bound. Variable `db-buffer' is bound to a buffer containing the database file. This is a global variable. If you set it to be specific to a particular database (for instance, in the format or auxiliary file), then consider having its last action be to reset the variable to `nil'. [Lame. --ttn] -- Variable: db-after-read-hooks Normal hook run after a database is completely read. The hooks are run in the data display buffer with variable `database' bound. For databases with nonregular layouts, you might put a call to `database-stored->actual' here, for instance. This is a global variable. If you set it to be specific to a particular database (for instance, in the format or auxiliary file), then consider having its last action be to reset the variable to `nil'. [Lame. --ttn]  File: edb.info, Node: Database mode hooks, Next: Record display hooks, Prev: Read hooks, Up: Hooks and customization functions 15.2.2 Database mode hooks -------------------------- EDB provides hooks that are run whenever the data display buffer is switched between Database View mode and Database Edit mode and which are run when a summary buffer is created. -- Variable: db-view-mode-hooks Normal hook run when Database View mode is entered. -- Variable: db-edit-mode-hooks Normal hook run when Database Edit mode is entered. -- Variable: database-summary-mode-hooks Normal hook run when switching to Database Summary mode. When using control properties, you should use `:locals' variables with the same name instead of setting the Emacs Lisp variables either directly or with `add-hook'. For example, here is a `.edb' file fragment: (defun set-up-1 () (setq truncate-lines t)) (defun set-up-2 () (scroll-bar-mode 1)) :locals [ (database-summary-mode-hooks '(set-up-1 set-up-2)) ] This arranges for the summary buffer to have a scroll bar and for its long lines to extend off screen. Note the square braces.  File: edb.info, Node: Record display hooks, Next: Edit mode hooks, Prev: Database mode hooks, Up: Hooks and customization functions 15.2.3 Record display hooks --------------------------- The following function is run each time a record is about to be displayed. This variable is set automatically when either of the control properties `:before-display' or `:choose-display' is specified (*note Control properties reference::). -- Variable: dbf-before-display-record-function A function called before a record is displayed. The function takes one argument, the record. This is a good place to put calls to `db-change-format'. Here is an example of how you might use this: (defun set-format-from-data (record) (if (< 0 (db-record-field record 'net-profit)) (db-change-format "loss format" "~/acct/db/loss.fmt") (db-change-format "profit format" "~/acct/db/profit.fmt"))) (setq dbf-before-display-record-function 'set-format-from-data) This uses two different display formats, depending on the value of one field of a record. As you move from record to record in the database, each one is shown using the appropriate display format. A preferable implementation hides the filenames from the calls to `db-change-format' and instead uses, in the format or auxiliary file, (setq dbf-format-name-spec-alist '(("loss format" . "~/acct/db/loss.fmt") ("profit format" . "~/acct/db/profit.fmt"))) See the example file `arb-demo.dba' for an example of this. `dbf-format-name-spec-alist' need not specify the full pathnames if the format files are located in the same directory as the database or if `"~/acct/db"' is placed in `db-format-file-path'. Finally, you would probably set a change hook on the net-profit field so that when its value changed, the record could be redisplayed in the appropriate format automatically. Here is an example of how to change the data display format in response to a particular field being changed. (defun equip-dbf-from-field (fieldname oldval newval) (let ((dbf-elt (assoc newval dbf-format-name-spec-alist)) (save-index dbf-this-field-index)) (db-change-format (if dbf-elt newval "default")) (setq dbf-this-field-index save-index) ; otherwise aref on nil ;; redisplay record t)) (setq db-after-read-hooks (lambda () (dbf-set-change-function 'equip-type 'equip-dbf-from-field)))  File: edb.info, Node: Edit mode hooks, Next: Display format change hooks, Prev: Record display hooks, Up: Hooks and customization functions 15.2.4 Edit mode hooks ---------------------- These hooks are called whenever you enter a field to edit it, which provides an easy way to customize the behavior of particular format fields. -- Variable: dbf-enter-field-hook Normal hook run whenever a display field is entered. The displayspec index is `dbf-this-field-index'. Note: For a `.edb' file (when using `edb-interact'), use the technique described in *note Database mode hooks::. It is sometimes advantageous to have a particular action happen only once per edit of a record. For instance, when a record's address, city, state, or zip-code fields are edited, we might like to copy all the values to the old-address, old-city, old-state, and old-zip-code fields. We only want this to happen once, however: if you edit first the address, then the city, we don't want to repeat the process, because then the old-address field would get written over by the new value of the address field. One way to prevent this from happening more than once is to set a variable when the copying is done, and then don't do the copying if that variable is set. The variable would be reset whenever a new record was edited. You can use `db-edit-mode-hooks' to do this job. (setq db-after-read-hooks (lambda () (set (make-local-variable 'db-edit-mode-hooks) (lambda () (dolist (var '(tep-homeaddr-oldified tep-homephone-oldified tep-bizaddr-oldified tep-bizphone-oldified)) (set (make-local-variable var) nil)))) (dbf-set-change-function 'home-phone 'tep-homephone-change-hook) (setq db-after-read-hooks nil))) (defvar tep-homephone-oldified nil) (defun tep-homephone-change-hook (fieldname oldval newval) (unless tep-homephone-oldified (dbf-this-record-set-field 'old-home-phone oldval)) ;; non-nil return value means redisplay whole record (prog1 (not tep-homephone-oldified) (setq tep-homephone-oldified t)))  File: edb.info, Node: Display format change hooks, Prev: Edit mode hooks, Up: Hooks and customization functions 15.2.5 Display format change hooks ---------------------------------- The following hook is run whenever a new record is created. This hook is set automatically when the control property `:record-defaults' is specified (*note Control properties reference::). -- Variable: db-new-record-function Function called on empty records before they're inserted in the database. Takes two arguments, the record and the database. A typical use is to set default information or add a timestamp. For instance: (defun set-update-date (record database) "Provide defaults for new records in the database." (db-record-set-field record 'updatedate (edb-t-timedate1:parse-date-string (current-date)) database)) (setq db-new-record-function 'set-update-date) The display format change hooks are called when you change a record field value. There are separate change hooks that run the first time any field is modified, whenever any field is modified, and whenever a particular field is modified. They run in the order `dbf-first-change-function', `dbf-every-change-function', and finally one of the elements set by `dbf-set-change-function'. Each change hook is either `nil' or a function of three variables: the fieldname of the just-modified field (a symbol) and the pre- and post-modification field values. These functions can set variable `dbf-redisplay-entire-record-p' to a non-`nil' value in order to cause the entire record to be redisplayed (for instance, if the change hook modifies fields other than that named by its first argument). -- Variable: dbf-first-change-function A function called the first time a record field is modified, or `nil'. The function takes the fieldname and the old and new values as arguments, and returns `t' if the record should be redisplayed. This variable is set automatically when the control property `:first-change-function' is specified (*note Control properties reference::). Here is an example of code to update the last modification field of a record, assuming its type is date: (defun update-last-modified-date (fieldname oldval newval) "Put the current date in this record's `last modified' field." (dbf-this-record-set-field 'last-modified (edb-t-timedate1:parse-date-string (current-date)))) (setq dbf-first-change-function 'update-last-modified-date) -- Variable: dbf-every-change-function A function called whenever a record field is modified, or `nil'. The function takes the fieldname and the old and new values as arguments, and returns `t' if the record should be redisplayed. This variable is set automatically when the control property `:every-change-function' is specified (*note Control properties reference::). -- Function: dbf-set-change-function fieldname function Set the change function for FIELDNAME to FUNCTION in the current database. FUNCTION takes the fieldname and the old and new values as arguments, and returns `t' if the record should be redisplayed. It is easy to make a field's value dependent on that of another field. For instance, suppose a salesman's commission should be 10% of the selling price of an item, and both fields are of type number. You could make the commission field unreachable (*note Display specification optional parameters::) and compute it whenever the selling price field varies. The latter operation could be done as follows: (defun set-commission (fieldname oldval newval) (dbf-displayed-record-set-field 'commission (/ newval 10))) (dbf-set-change-function 'selling-price 'set-commission) There are two things to notice about this example. First, we need not set `dbf-redisplay-entire-record-p', as `dbf-displayed-record-set-field' does that automatically. Second, if we replaced `newval' by `(dbf-displayed-record-field 'selling-price)', then the function would work even if not called as a change function for selling-price. You may modify records explicitly by calling `dbf-displayed-record-set-field' (*note Manipulating records::); when that is done, the following hook is invoked. It is different from the above functions in that they are called when you edit a field, while it is called when Emacs Lisp code modifies a field (usually as a result of some interactive command). -- Variable: dbf-set-this-record-modified-function A function called when the current record is marked as modified. The function takes no arguments and its return value is ignored. It is called after the original record values are copied to the working record. Another function is invoked when changes to a record are committed -- that is, when changes to the record which is being displayed are copied back into its original in the database. -- Variable: dbf-after-record-change-function Function called whenever changes to a record are recorded semi-permanently. The function takes the record as an argument. Its return value is ignored. Note: To achieve the same effect as setting these two variables for a `.edb' file (when using `edb-interact'), use the technique described in *note Database mode hooks::.  File: edb.info, Node: Global variables, Prev: Hooks and customization functions, Up: Customization 15.3 Global variables ===================== This section describes some customization variables which you can use to understand and (if lucky) control EDB's behavior. When a potentially slow computation is underway, EDB displays a message in the echo area reporting how many records have been processed. Use the following variable to control how often this message is updated. -- Variable: db-inform-interval When doing a lengthy computation, display a progress message in the echo area every this many records. If `nil', don't inform. Note: For a `.edb' file (when using `edb-interact'), use the technique described in *note Database mode hooks::.  File: edb.info, Node: Database representation, Next: Naming conventions, Prev: Customization, Up: Top 16 Database representation ************************** Perhaps the most important information about a database -- besides the records it contains -- is the number of fields in each record, and the type of each field. As explained previously (*note Terminology and concepts::), a database consists of records with identical numbers of fields; each field has an associated type such as string or integer. Each field also has a name which is used when extracting its value from the record. Internally, records and metainfo about them (individually and in aggregate) are represented by various vectors and hash tables; however, you should never manipulate those structures directly, only through the functions described in this chapter. -- Variable: dbc-database This is a buffer-local variable that contains the "current database". Given a record, it is not possible to determine which database (if any) it belongs to. The database-to-record connection is one-way. * Menu: * Mapping over the database:: * Manipulating records::  File: edb.info, Node: Mapping over the database, Next: Manipulating records, Up: Database representation 16.1 Mapping over the database ============================== Mapping refers to applying a function to each record in the database, or executing a piece of code for each record. -- Function: db-maprecords func [database [hide [message [accumulate]]]] Apply FUNC to every record in the current database in order of ascending index. Optional second arg DB specifies a database to use other than the current one. If optional third arg HIDE is non-`nil', apply FUNC only to unhidden records. If optional fourth arg MESSAGE is non-`nil', it should be a format string containing one numeric (%d) specifier. That message will be issued every `db-inform-interval' records. If optional fifth arg ACCUMULATE is non-`nil', return a list of the results; otherwise return `nil'. There is also the alias `maprecords' for old code. (If you can help it, use `db-maprecords' instead.) For instance, to sum, for all records, the values contained in field `summand' (of type `number'), you could use either of the following forms: (let ((result 0)) (db-maprecords (lambda (record) (setq result (+ result (db-record-field record 'summand))))) result) (apply (function +) (db-maprecords (lambda (record) (db-record-field record 'summand)) nil nil nil t))  File: edb.info, Node: Manipulating records, Prev: Mapping over the database, Up: Database representation 16.2 Manipulating records ========================= A database consists of records, each of which has the same makeup: corresponding fields in a database's records contain data of the same type. For instance, the fifth field of each record might contain an address, and the seventh field, a date. The particular addresses and dates would would vary from record to record. (Different databases will contain records with different numbers and types of fields.) Each field has a name and a type, which specifies what sort of information can be stored in the field; for more details about record field types, *Note Record field types::. Records are represented internally as vectors, but should never be operated on as such; use the abstractions described in this section. 16.2.1 Creating and copying records ----------------------------------- -- Function: db-make-record database init Return a DATABASE-specific record initialized with INIT. INIT is either a list of alternating field names (symbols) and values, or a list whose car is the keyword `:alist' and whose cdr is an alist mapping field names to their values. When you create a new record by using `db-add-record' (*note Adding and removing records::), `db-new-record-function' is invoked (*note Display format change hooks::), the number of records in the database is modified, and so forth. `db-make-record', on the other hand, performs none of these housekeeping tasks. 16.2.2 Accessing record fields ------------------------------ Ordinarily, record fields are accessed by specifying the name of the desired field; the database must also be specified so that the fieldname-to-fieldnumber correspondence can be determined. -- Function: db-record-field record fieldname [database] Return from RECORD the field with name FIELDNAME. If RECORD is t, use the "current record". Optional third argument DATABASE specifies a database other than the current one. -- Function: db-record-set-field record fieldname value [database [nocheck]] Set, in RECORD, field FIELDNAME to VALUE. Fourth argument is DATABASE. Check constraints first unless optional fifth argument NOCHECK is non-`nil'. There are also special commands for manipulating the current record -- that is, the one that appears in the data display buffer. These functions require fewer arguments, flag that a redisplay of the record is necessary, and automatically call `dbf-set-this-record-modified-p', which is essential if the changes are to be copied back into the original record in the database from the one that is being displayed. (A copy is always displayed so that changes can be undone.) -- Function: dbf-displayed-record Return the record currently displayed in this data display buffer. This may either be the working copy, if the record has been marked as modified, or the original otherwise. -- Function: dbf-displayed-record-field fieldname Return the value of the field named FIELDNAME from the displayed record. -- Function: dbf-displayed-record-set-field fieldname value Set field with name FIELDNAME in displayed record to VALUE. Cause the entire record to be redisplayed soon. -- Function: dbf-displayed-record-set-field-and-redisplay fieldname value Set field with name FIELDNAME in displayed record to VALUE. Cause the entire record to be redisplayed immediately. -- Function: dbf-set-this-record-modified-p arg Mark the current record as modified if ARG is non-`nil'. If the record was previously not marked as modified, make a copy of the original, and call `dbf-set-this-record-modified-function'.  File: edb.info, Node: Naming conventions, Next: In case of trouble, Prev: Database representation, Up: Top 17 Naming conventions ********************* EDB makes use of several namespaces: Emacs lisp functions and variables, file names, and type names. To reduce confusion, names have been chosen following some conventions, described in this chapter. 17.1 Function and variable naming conventions ============================================= Functions and variables begin with one of the following prefixes. `edb-t-GROUP:' Functions or variables supporting some "type group" (for lack of a better name). Note the trailing `:'. The type names themselves do not presently follow any conventions, although that may change in the future with EDB 2.x. `edb-' Data structures and functions related to the (meta) binding behavior. Many of these have two hyphens instead of one, which means the item is "internal" in some sense; its definition may change without warning from one EDB release to the next. `db-' In a variable, indicates that the variable is global and affects all databases. It is also used in some situations for internal database functionality which is not connected with any particular buffer. `database-' These functions operate on (the internal representation of) the database structure itself. `dbc-' Indicates a variable local to the data display buffer which refers to the current database (the database being manipulated by that data display buffer). The `c' stands for "current." `dbf-' Indicates a variable local to the data display buffer which controls some aspect of formatting. The `f' stands for "format"; many such variables are intimately related to the format, and the data display buffer used to be called the format buffer. `dbs-' Indicates a variable local to the summary buffer, or a summary buffer function. Since the summary buffer may disappear at any time, the summary buffer gets most of its information from the associated data display buffer's local variables. `dbsi-' Indicates a variable local to a sort interface buffer, or a sort interface function. 17.2 File naming conventions ============================ By convention, database file names contain one of the following suffixes: `edb-t-GROUP.el' Contains forms that implement a type group (see above). `.dat' These are database files proper; they contain the information that makes up the fields and records of the database. Database filenames may also contain no extension at all. `.fmt' Format files control the structure of the data display buffer, which displays one record at a time. `.dba' Auxiliary files contain arbitrary Emacs Lisp code; they can be used to define functions, set variables, or operate directly on the database. Other suffixes -- or none at all -- can be easily used; for instance, see variables `db-format-file-suffixes' and `db-aux-file-suffixes' (*note Auxiliary files::). For more information, *Note Invoking EDB::. 17.3 Type naming conventions ============================ There is only one minor naming convention for types: `BASE-or-nil' usually means that handling for the type is very similar to handling for type BASE with special handling in case the value is `nil'.  File: edb.info, Node: In case of trouble, Next: Function Index, Prev: Naming conventions, Up: Top 18 In case of trouble ********************* 18.1 Variables ============== In some cases the documentation strings and/or default values of some variables may be missing -- as if the variables were not yet defined. That's because the variables are not yet defined; they are associated with part of EDB which hasn't been loaded because it hasn't been needed yet. The documentation and default values will appear when that part of EDB is loaded (if you set such variables, your values will not be replaced). Such variables are correctly declared buffer-local (if appropriate), so you can set them without fear of the changes affecting other buffers. 18.2 Exiting Emacs or saving files ================================== If you are unable to exit Emacs or to execute `db-save-some-buffers' because Emacs is trying to manipulate a database which doesn't exist or because an EDB bug is triggered by the attempt to save an existing database, you can set variable `edb--global-state' to nil and reload `edbcore.elc'. [TODO: Write a reset command; document it here. -ttn] This indicates to EDB that there are no databases read into memory and, therefore, no operations will be attempted on them as a part of saving all modified Emacs buffers. 18.3 Poking Around ================== If things get really weird, you can try to use the command `edb-meta' and include the result in a bug report to the EDB maintainer. -- Function: edb-meta Summarize EDB state in a new buffer, and switch to it. The output format is likely to change from one release of EDB to the next; do not rely on it.  File: edb.info, Node: Function Index, Next: Variable Index, Prev: In case of trouble, Up: Top Function Index ************** [index] * Menu: * database-set-fieldnames-to-list: Specifying a record field type. (line 12) * database-sort: Record field attributes. (line 36) * database-stored->actual: Read hooks. (line 26) * db-accept-record: Making changes permanent. (line 21) * db-add-record: Adding and removing records. (line 9) * db-additional-data-display-buffer: Making additional data display buffers. (line 17) * db-change-format: Changing display formats. (line 15) * db-copy-record: Adding and removing records. (line 16) * db-delete-record: Adding and removing records. (line 29) * db-exit: Exiting database mode. (line 24) * db-field-help: Getting help. (line 12) * db-find-file: Invoking EDB. (line 87) * db-first-field: Changing to Database Edit mode. (line 16) * db-first-record: Moving around in the database. (line 19) * db-hide-record: Setting the mark and hide bits. (line 20) * db-hide-unmarked-records: Setting the mark and hide bits. (line 36) * db-hiding-set: Details of hiding. (line 37) * db-hiding-toggle: Details of hiding. (line 20) * db-jump-to-record: Moving around in the database. (line 30) * db-kill-all-buffers: Exiting database mode. (line 18) * db-kill-buffer: Exiting database mode. (line 12) * db-last-field: Changing to Database Edit mode. (line 21) * db-last-record: Moving around in the database. (line 25) * db-make-n-line-sep-function: How to specify delimited file layouts. (line 98) * db-make-record: Manipulating records. (line 23) * db-maprecords: Mapping over the database. (line 11) * db-mark-record: Setting the mark and hide bits. (line 14) * db-mark-unhidden-records: Setting the mark and hide bits. (line 42) * db-next-field: Moving from field to field. (line 8) * db-next-line-or-field: Movement within a field. (line 15) * db-next-marked-record: Movement among marked and hidden records. (line 25) * db-next-record: Moving around in the database. (line 8) * db-next-record-ignore-hiding: Movement among marked and hidden records. (line 15) * db-next-screen-or-record: Moving around in the database. (line 39) * db-output-record-to-db: Adding and removing records. (line 23) * db-previous-field: Moving from field to field. (line 13) * db-previous-line-or-field: Movement within a field. (line 21) * db-previous-marked-record: Movement among marked and hidden records. (line 30) * db-previous-record: Moving around in the database. (line 13) * db-previous-record-ignore-hiding: Movement among marked and hidden records. (line 20) * db-previous-screen-or-record: Moving around in the database. (line 46) * db-quit: Exiting database mode. (line 8) * db-rdb-correlate-field-defs: Relational file layout. (line 38) * db-rdb-database-stored->actual: Relational file layout. (line 18) * db-rdb-list-rrfr: Relational file layout. (line 18) * db-rdb-list-wrfr: Relational file layout. (line 18) * db-rdb-read-fields: Relational file layout. (line 18) * db-rdb-setup: Relational file layout. (line 22) * db-record-field: Manipulating records. (line 42) * db-record-set-field: Manipulating records. (line 48) * db-report: Reports. (line 11) * db-revert-database: Undoing all changes to a record. (line 14) * db-revert-field: Undoing changes to a field. (line 16) * db-revert-record: Undoing all changes to a record. (line 8) * db-save-some-buffers: In case of trouble. (line 29) * db-search: Searching. (line 33) * db-search-field: Searching. (line 20) * db-set-field-help: Specifying a record field type. (line 61) * db-sort: Sort interface. (line 11) * db-summary: Database Summary mode. (line 15) * db-tagged-setup: Tagged file layout. (line 27) * db-toggle-internal-file-layout: Internal file layout details. (line 32) * db-toggle-modifiable-p: Database Edit mode. (line 15) * db-toggle-show-hidden-records: Details of hiding. (line 30) * db-unhide-all: Setting the mark and hide bits. (line 50) * db-unmark-all: Setting the mark and hide bits. (line 47) * db-view-mode: Exiting Database Edit mode. (line 8) * dbf-always: Execution of format file eval expressions. (line 16) * dbf-displayed-record: Manipulating records. (line 61) * dbf-displayed-record-field: Manipulating records. (line 66) * dbf-displayed-record-set-field: Manipulating records. (line 70) * dbf-displayed-record-set-field-and-redisplay: Manipulating records. (line 75) * dbf-set-change-function: Display format change hooks. (line 70) * dbf-set-summary-format: Database Summary mode. (line 59) * dbf-set-this-record-modified-p: Manipulating records. (line 79) * dbsi-decreasing: Sort interface. (line 71) * dbsi-increasing: Sort interface. (line 66) * dbsi-kill-line: Sort interface. (line 46) * dbsi-ordering-function: Sort interface. (line 76) * dbsi-quit: Sort interface. (line 129) * dbsi-quit-clear-buffer-default: Sort interface. (line 133) * dbsi-sorting-function: Sort interface. (line 83) * dbsi-this-field-only: Sort interface. (line 124) * dbsi-toggle-hidden-to-end: Sort interface. (line 37) * dbsi-use-ordering: Sort interface. (line 120) * dbsi-use-ordering-make-buffer-default: Sort interface. (line 113) * dbsi-use-ordering-make-database-default: Sort interface. (line 106) * dbsi-yank-line: Sort interface. (line 52) * edb-1int-to-single: edb-1int-to-single. (line 14) * edb-define-displaytype: Defining new displaytypes. (line 18) * edb-define-enumtype: Enumeration displaytypes. (line 24) * edb-define-recordfieldtype: Specifying a record field type. (line 43) * edb-get: Changing control properties at runtime. (line 11) * edb-interact: Invoking EDB. (line 36) * edb-meta: In case of trouble. (line 38) * edb-put: Changing control properties at runtime. (line 16) * edb-t-timedate1:date-day: Predefined displaytypes. (line 62) * edb-t-timedate1:date-month: Predefined displaytypes. (line 62) * edb-t-timedate1:date-year: Predefined displaytypes. (line 62) * edb-t-timedate1:format-date: Predefined displaytypes. (line 83) * edb-t-timedate1:format-time: Predefined displaytypes. (line 164) * edb-t-timedate1:format-time-12: Predefined displaytypes. (line 186) * edb-t-timedate1:format-time-12-hhmm: Predefined displaytypes. (line 189) * edb-t-timedate1:format-time-24: Predefined displaytypes. (line 187) * edb-t-timedate1:format-time-24-hhmm: Predefined displaytypes. (line 190) * edb-t-timedate1:format-time-hhmm: Predefined displaytypes. (line 188) * edb-t-timedate1:make-date: Predefined displaytypes. (line 72) * edb-t-timedate1:make-time: Predefined displaytypes. (line 175) * edb-t-timedate1:parse-date-default-function: Predefined displaytypes. (line 75) * edb-t-timedate1:parse-date-string: Predefined displaytypes. (line 76) * edb-t-timedate1:parse-time-default-function: Predefined displaytypes. (line 178) * edb-t-timedate1:parse-time-string: Predefined displaytypes. (line 164) * edb-t-timedate1:simple-format-date <1>: Predefined displaytypes. (line 133) * edb-t-timedate1:simple-format-date: Predefined record field types. (line 86) * edb-t-timedate1:storage-string->date: Predefined record field types. (line 86) * edb-tag: Setting the mark and hide bits. (line 58) * edb-tag-: Setting the mark and hide bits. (line 70) * edb-tagp: Setting the mark and hide bits. (line 64) * edb-tagx: Setting the mark and hide bits. (line 67) * right-justify: Display specification optional parameters. (line 84)  File: edb.info, Node: Variable Index, Next: Concept Index, Prev: Function Index, Up: Top Variable Index ************** [index] * Menu: * :before-display control property: Control properties reference. (line 154) * :choose-display control property: Control properties reference. (line 147) * :continuation db-tagged-setup keyword: Tagged file layout. (line 88) * :continuation-output db-tagged-setup keyword: Tagged file layout. (line 98) * :continuation-regexp db-tagged-setup keyword: Tagged file layout. (line 94) * :cruft control property: Control properties reference. (line 102) * :data control property: Control properties reference. (line 109) * :default-field db-tagged-setup keyword: Tagged file layout. (line 121) * :display control property: Control properties reference. (line 18) * :every-change-function control property: Control properties reference. (line 180) * :field-order control property: Control properties reference. (line 185) * :field-separator control property: Control properties reference. (line 83) * :fields control property: Control properties reference. (line 26) * :first-change-function control property: Control properties reference. (line 175) * :index-function db-tagged-setup keyword: Tagged file layout. (line 106) * :locals control property: Control properties reference. (line 199) * :name control property: Control properties reference. (line 170) * :post-write-function db-tagged-setup keyword: Tagged file layout. (line 117) * :pre-parse-thunk db-tagged-setup keyword: Tagged file layout. (line 101) * :pre-write-function db-tagged-setup keyword: Tagged file layout. (line 113) * :read-record control property: Control properties reference. (line 48) * :record-defaults control property: Control properties reference. (line 206) * :record-separator control property: Control properties reference. (line 79) * :record-separator-function control property: Control properties reference. (line 63) * :record-terminator control property: Control properties reference. (line 74) * :report control property: Control properties reference. (line 160) * :separator db-tagged-setup keyword: Tagged file layout. (line 76) * :separator-output db-tagged-setup keyword: Tagged file layout. (line 85) * :separator-regexp db-tagged-setup keyword: Tagged file layout. (line 81) * :substitution-separators control property: Control properties reference. (line 87) * :substitutions control property: Control properties reference. (line 95) * :summary-format control property: Control properties reference. (line 163) * :tag-chars db-tagged-setup keyword: Tagged file layout. (line 71) * :tagged-setup control property: Control properties reference. (line 32) * :write-record control property: Control properties reference. (line 56) * database-summary-mode-hooks: Database mode hooks. (line 17) * db-after-read-hooks: Read hooks. (line 24) * db-aux-file-path: Auxiliary files. (line 33) * db-aux-file-suffixes: Auxiliary files. (line 27) * db-before-read-hooks: Read hooks. (line 13) * db-default-field-type: Specifying a record field type. (line 22) * db-edit-mode-hooks: Database mode hooks. (line 14) * db-format-file-path: Auxiliary files. (line 74) * db-format-file-suffixes: Auxiliary files. (line 68) * db-inform-interval: Global variables. (line 14) * db-new-record-function: Display format change hooks. (line 11) * db-sort-modifies-p: Sort interface. (line 147) * db-view-mode-hooks: Database mode hooks. (line 11) * dbc-database: Database representation. (line 20) * dbf-after-record-change-function: Display format change hooks. (line 112) * dbf-before-display-record-function: Record display hooks. (line 12) * dbf-enter-field-hook: Edit mode hooks. (line 11) * dbf-every-change-function: Display format change hooks. (line 61) * dbf-first-change-function: Display format change hooks. (line 40) * dbf-format-name-spec-alist: Changing display formats. (line 41) * dbf-redisplay-entire-record-p: Display format change hooks. (line 37) * dbf-set-this-record-modified-function: Display format change hooks. (line 102) * edb-data-coding: Data encoding. (line 12)  File: edb.info, Node: Concept Index, Prev: Variable Index, Up: Top Concept Index ************* [index] * Menu: * .dat file suffix: Invoking EDB. (line 55) * .dba file suffix: Invoking EDB. (line 55) * .edb files: Invoking EDB. (line 30) * .fmt file suffix: Invoking EDB. (line 55) * :actual->stored record field attribute: Record field attributes. (line 66) * :common-form-function record field attribute: Record field attributes. (line 25) * :constraint-function record field attribute: Record field attributes. (line 76) * :default-value record field attribute: Record field attributes. (line 21) * :help-info record field attribute: Record field attributes. (line 60) * :match-function record field attribute: Record field attributes. (line 55) * :merge-function record field attribute: Record field attributes. (line 31) * :order-function record field attribute: Record field attributes. (line 36) * :sort-function record field attribute: Record field attributes. (line 36) * :stored->actual record field attribute: Record field attributes. (line 70) * :type record field attribute: Record field attributes. (line 13) * <, in search pattern: Searching. (line 63) * =, in search pattern: Searching. (line 63) * >, in search pattern: Searching. (line 63) * a->d display specification parameter: Display specification optional parameters. (line 103) * accepting changes: Making changes permanent. (line 6) * accessing record fields: Manipulating records. (line 37) * actual->display displayspec slot: Display specification optional parameters. (line 102) * adding a record: Adding and removing records. (line 6) * additional data display buffers, making: Making additional data display buffers. (line 6) * alternate display formats: Changing display formats. (line 6) * ambiguities in database files, resolving: Resolving ambiguities. (line 6) * auxiliary file: Auxiliary files. (line 6) * auxiliary file name: Auxiliary files. (line 23) * beginning of file, text at: How to specify delimited file layouts. (line 22) * boolean record field type: Predefined record field types. (line 37) * Botswana: Nonregular database example. (line 63) * change hooks, for display formats: Display format change hooks. (line 6) * changes, accepting them: Making changes permanent. (line 6) * changes, committing them: Making changes permanent. (line 6) * changes, making them permanent: Making changes permanent. (line 6) * changing display formats: Changing display formats. (line 6) * characteristics, control property values: Kinds of control property values. (line 6) * coding system: Data encoding. (line 6) * committing changes: Making changes permanent. (line 6) * control buffer: Invoking EDB. (line 30) * control file: Invoking EDB. (line 30) * control file examples: Example control file from scratch. (line 6) * control properties: Specifying control. (line 6) * control properties reference: Control properties reference. (line 6) * control properties, interpretation: Interpreting control properties. (line 6) * control without control properties: Ongoing migration. (line 6) * converting a file to or from EDB internal layout: Internal file layout details. (line 24) * copying records: Manipulating records. (line 22) * creating records: Manipulating records. (line 22) * customization: Customization. (line 6) * customization functions: Hooks and customization functions. (line 6) * customization, global variables: Global variables. (line 6) * d->a display specification parameter: Display specification optional parameters. (line 103) * data display buffer, hiding fields: Changing display formats. (line 63) * data display buffers, making additional: Making additional data display buffers. (line 6) * data encoding: Data encoding. (line 6) * data file layout: Database file layout. (line 6) * data file layout, delimited: Delimited file layout. (line 6) * data file layout, internal: Internal file layout. (line 6) * data file layout, nonregular: Nonregular file layout. (line 6) * data file layout, relational: Relational file layout. (line 6) * data file layout, tagged: Tagged file layout. (line 6) * data-dependent display format: Record display hooks. (line 6) * Database Edit mode: Database Edit mode. (line 6) * database file layout: Database file layout. (line 6) * database files, editing: Database mode. (line 19) * database mode hooks: Database mode hooks. (line 6) * database representation: Database representation. (line 6) * Database Summary mode: Database Summary mode. (line 6) * Database View mode: Database View mode. (line 6) * date displaytype: Predefined displaytypes. (line 62) * date record field type: Predefined record field types. (line 72) * date-all displaytype: Predefined displaytypes. (line 158) * date-ddmmmyy displaytype: Predefined displaytypes. (line 142) * date-ddmmyy displaytype: Predefined displaytypes. (line 141) * date-dec displaytype: Predefined displaytypes. (line 160) * date-efficient-storage record field type: Predefined record field types. (line 86) * date-europe displaytype: Predefined displaytypes. (line 156) * date-full displaytype: Predefined displaytypes. (line 157) * date-iso displaytype: Predefined displaytypes. (line 155) * date-mmddyy displaytype: Predefined displaytypes. (line 139) * date-or-nil record field type: Predefined record field types. (line 83) * date-unix displaytype: Predefined displaytypes. (line 159) * date-yymmdd displaytype: Predefined displaytypes. (line 140) * date-yyyymmdd displaytype: Predefined displaytypes. (line 143) * defining displaytypes: Defining new displaytypes. (line 6) * deleting a record: Adding and removing records. (line 6) * delimited file layout: Delimited file layout. (line 6) * delimiters, record and field: Delimited file layout. (line 13) * dependent field values: Display format change hooks. (line 74) * details, implementation: Organization of this manual. (line 24) * display format change hooks: Display format change hooks. (line 6) * display format file name: Auxiliary files. (line 6) * display format, alternate: Changing display formats. (line 6) * display format, data-dependent: Record display hooks. (line 6) * display format, selecting: Specifying the display format. (line 6) * display format, specifying: How information is displayed. (line 6) * display format, variant: Changing display formats. (line 6) * display specification: Display specifications. (line 6) * display specification optional parameters: Display specification optional parameters. (line 6) * display->actual displayspec slot: Display specification optional parameters. (line 103) * displayspec fields: Display specification optional parameters. (line 6) * displayspec structure: Display specification optional parameters. (line 29) * displaytype, compared to record field type: Record field types. (line 23) * displaytype, defining: Defining new displaytypes. (line 6) * displaytype, not set by display specification: Display specifications. (line 49) * displaytypes, predefined: Predefined displaytypes. (line 6) * documentation to be deleted: Organization of this manual. (line 24) * EDB internal layout, converting to or from: Internal file layout details. (line 24) * edit mode: Database Edit mode. (line 6) * edit mode hooks: Edit mode hooks. (line 6) * editing database files: Database mode. (line 19) * Einstein, Albert: Nonregular database example. (line 63) * encoding, data: Data encoding. (line 6) * end of file, text at: How to specify delimited file layouts. (line 22) * enforcing constraints: Record field attributes. (line 76) * enumeration types: Enumeration displaytypes. (line 6) * eval expressions, in format file: Execution of format file eval expressions. (line 6) * example, new control: New control example. (line 6) * exiting database mode: Exiting database mode. (line 6) * exiting Emacs, trouble with: In case of trouble. (line 22) * field delimiters: Delimited file layout. (line 13) * field separator, setting: How to specify delimited file layouts. (line 6) * field type, record: Record field types. (line 6) * fields, accessing them in records: Manipulating records. (line 37) * fields, reading them in records: Manipulating records. (line 37) * fields, setting them in records: Manipulating records. (line 37) * fieldspec, see record field attributes: Record field attributes. (line 6) * file format for data file: Database file layout. (line 6) * file layout: Database file layout. (line 6) * file layout for data file: Database file layout. (line 6) * file layout, delimited: Delimited file layout. (line 6) * file layout, internal: Internal file layout. (line 6) * file layout, nonregular: Nonregular file layout. (line 6) * file layout, relational: Relational file layout. (line 6) * file layout, tagged: Tagged file layout. (line 6) * file name, for auxiliary file: Auxiliary files. (line 6) * file name, for display format: Auxiliary files. (line 6) * file naming conventions: Naming conventions. (line 61) * files used by EDB: Invoking EDB. (line 6) * files, editing database: Database mode. (line 19) * floating-point number displaytype: Predefined displaytypes. (line 24) * floating-point number record field type: Predefined record field types. (line 28) * format file: Auxiliary files. (line 6) * format file name: Auxiliary files. (line 61) * format file, eval expressions in: Execution of format file eval expressions. (line 6) * format file, local variables section: Execution of format file eval expressions. (line 6) * format file, path to search: Auxiliary files. (line 67) * format file, primary: Execution of format file eval expressions. (line 6) * format, of data file: Database file layout. (line 6) * format-spec structure: Changing display formats. (line 40) * function naming conventions: Naming conventions. (line 13) * function whose arglist specifies field names (type): Kinds of control property values. (line 11) * height display specification parameter: Display specification optional parameters. (line 69) * help for record fields: Getting help. (line 6) * hiding: Marking and hiding. (line 6) * hiding fields from a data display buffer: Changing display formats. (line 63) * hooks: Hooks and customization functions. (line 6) * hooks, change, for display formats: Display format change hooks. (line 6) * hooks, database modes: Database mode hooks. (line 6) * hooks, edit mode: Edit mode hooks. (line 6) * hooks, record display: Record display hooks. (line 6) * implementation details: Organization of this manual. (line 24) * indent displayspec slot: Display specification optional parameters. (line 35) * inserting a record: Adding and removing records. (line 6) * integer displaytype: Predefined displaytypes. (line 17) * integer record field type: Predefined record field types. (line 20) * integer-or-nil displaytype: Predefined displaytypes. (line 20) * integer-or-nil record field type: Predefined record field types. (line 23) * internal data file layout: Internal file layout. (line 6) * interpreting control properties: Interpreting control properties. (line 6) * invoking EDB: Invoking EDB. (line 6) * justification of display fields: Display specification optional parameters. (line 84) * killing a database buffer: Exiting database mode. (line 6) * killing a record: Adding and removing records. (line 6) * kinds, control property values: Kinds of control property values. (line 6) * last modification field: Display format change hooks. (line 49) * layout, of data file: Database file layout. (line 6) * left justification of display fields: Display specification optional parameters. (line 84) * local variables section of format file: Execution of format file eval expressions. (line 6) * local variables section, format file: Nonregular database example. (line 49) * looping over the database: Mapping over the database. (line 6) * making changes permanent: Making changes permanent. (line 6) * mapping over the database: Mapping over the database. (line 6) * marking: Marking and hiding. (line 6) * match-actual->display displayspec slot: Display specification optional parameters. (line 134) * match-display->actual displayspec slot: Display specification optional parameters. (line 135) * max-height displayspec slot: Display specification optional parameters. (line 69) * max-width displayspec slot: Display specification optional parameters. (line 56) * min-height displayspec slot: Display specification optional parameters. (line 68) * min-width displayspec slot: Display specification optional parameters. (line 55) * mode line: Database mode. (line 35) * moving from field to field: Moving from field to field. (line 6) * moving from record to record: Moving around in the database. (line 6) * naming conventions: Naming conventions. (line 6) * new control example: New control example. (line 6) * new records, setting default information: Display format change hooks. (line 14) * newline, at end of database file: Problems with end-of-file newlines. (line 6) * nil-or-string displaytype: Predefined displaytypes. (line 48) * nil-or-string record field type: Predefined record field types. (line 52) * noindent display specification parameter: Display specification optional parameters. (line 35) * nonregular file layout: Nonregular file layout. (line 6) * number displaytype: Predefined displaytypes. (line 24) * number record field type: Predefined record field types. (line 28) * number-or-nil displaytype: Predefined displaytypes. (line 28) * number-or-nil record field type: Predefined record field types. (line 32) * one-line-string displaytype: Predefined displaytypes. (line 41) * one-line-string record field type: Predefined record field types. (line 45) * one-line-string-or-nil displaytype: Predefined displaytypes. (line 53) * one-line-string-or-nil record field type: Predefined record field types. (line 57) * ongoing migration: Ongoing migration. (line 6) * ordering functions: Sorting functions. (line 6) * padding-action displayspec slot: Display specification optional parameters. (line 84) * predefined displaytypes: Predefined displaytypes. (line 6) * predefined record field types: Predefined record field types. (line 6) * primary format file: Execution of format file eval expressions. (line 6) * quitting database mode: Exiting database mode. (line 6) * reachablep displayspec slot: Display specification optional parameters. (line 152) * reading a database from disk: Invoking EDB. (line 81) * reading from disk, details: Reading from disk. (line 6) * reading record fields: Manipulating records. (line 37) * record delimiters: Delimited file layout. (line 13) * record display hooks: Record display hooks. (line 6) * record field attributes: Record field attributes. (line 6) * record field index: Display specification optional parameters. (line 30) * record field type: Record field types. (line 6) * record field type, compared to displaytype: Record field types. (line 23) * record field type, specifying: Specifying a record field type. (line 6) * record field types, predefined: Predefined record field types. (line 6) * record fields, accessing: Manipulating records. (line 37) * record initializer function (type): Kinds of control property values. (line 64) * record representation: Manipulating records. (line 6) * record separator, setting: How to specify delimited file layouts. (line 6) * record-index displayspec slot: Display specification optional parameters. (line 30) * relational file layout: Relational file layout. (line 6) * removing a record: Adding and removing records. (line 6) * reports: Reports. (line 6) * representation of database: Database representation. (line 6) * resolving ambiguities in database files: Resolving ambiguities. (line 6) * reverting changes to a field: Undoing changes to a field. (line 6) * reverting changes to a record: Undoing all changes to a record. (line 6) * right justification of display fields: Display specification optional parameters. (line 84) * right-justify display specification parameter: Display specification optional parameters. (line 84) * saving files, trouble with: In case of trouble. (line 22) * saving to disk: Invoking EDB. (line 95) * search commands: Searching. (line 15) * search patterns: Searching. (line 42) * searching: Searching. (line 6) * selecting only some records: Marking and hiding. (line 6) * separator, setting field: How to specify delimited file layouts. (line 6) * separator, setting record: How to specify delimited file layouts. (line 6) * setting record fields: Manipulating records. (line 37) * simultaneously manipulating two records: Making additional data display buffers. (line 6) * simultaneously using two formats: Making additional data display buffers. (line 6) * slot assigners, for display specifications: Display specification optional parameters. (line 10) * slotsetters, for display specifications: Display specification optional parameters. (line 10) * sorting: Sorting. (line 6) * sorting functions: Sorting functions. (line 6) * specifier, format: Changing display formats. (line 40) * specifying a record field type: Specifying a record field type. (line 6) * specifying control: Specifying control. (line 6) * starting up EDB: Invoking EDB. (line 81) * string displaytype: Predefined displaytypes. (line 36) * string or regexp vector (type): Kinds of control property values. (line 42) * string record field type: Predefined record field types. (line 42) * string-or-nil displaytype: Predefined displaytypes. (line 44) * string-or-nil record field type: Predefined record field types. (line 48) * substitution, in reading a database file: Resolving ambiguities. (line 52) * summary format, setting: Database Summary mode. (line 45) * summary mode: Database Summary mode. (line 6) * tab-separated text file layout: Delimited file layout. (line 6) * tagged file layout: Tagged file layout. (line 6) * text-block specification (type): Kinds of control property values. (line 16) * three file types used by EDB: Invoking EDB. (line 55) * time displaytype: Predefined displaytypes. (line 164) * time record field type: Predefined record field types. (line 95) * trouble with exiting Emacs: In case of trouble. (line 22) * trouble with saving files: In case of trouble. (line 22) * trouble with undefined variables: In case of trouble. (line 9) * trunc-display display specification parameter: Display specification optional parameters. (line 75) * trunc-edit display specification parameter: Display specification optional parameters. (line 146) * truncation-display-action displayspec slot: Display specification optional parameters. (line 75) * truncation-editing-action displayspec slot: Display specification optional parameters. (line 146) * two formats, using simultaneously: Making additional data display buffers. (line 6) * two records, manipulating simultaneously: Making additional data display buffers. (line 6) * type naming conventions: Naming conventions. (line 90) * type, display, defining: Defining new displaytypes. (line 6) * type, display, predefined: Predefined displaytypes. (line 6) * type, record field: Record field types. (line 6) * type, specifying record field: Specifying a record field type. (line 6) * undoing changes to a field: Undoing changes to a field. (line 6) * undoing changes to a record: Undoing all changes to a record. (line 6) * uneditable fields in data display buffer: Display specification optional parameters. (line 152) * unreachable display specification parameter: Display specification optional parameters. (line 152) * variable default value missing: In case of trouble. (line 9) * variable documentation missing: In case of trouble. (line 9) * variable naming conventions: Naming conventions. (line 13) * variant display formats: Changing display formats. (line 6) * View mode, Database: Database View mode. (line 6) * width display specification parameter: Display specification optional parameters. (line 56) * writing to disk: Invoking EDB. (line 95) * WWW Links control file examples: Example control file from scratch. (line 6) * yes-no displaytype: Predefined displaytypes. (line 32)  Tag Table: Node: Top844 Node: Introduction4439 Node: Organization of this manual6955 Node: Terminology and concepts8334 Node: Invoking EDB11135 Node: Example EDB session16010 Node: Database mode19744 Ref: Database mode-Footnote-123910 Node: Database View mode24072 Node: Moving around in the database24814 Node: Changing to Database Edit mode26626 Node: Undoing all changes to a record27350 Node: Making changes permanent28056 Node: Adding and removing records29463 Node: Exiting database mode30600 Node: Database Edit mode31496 Node: Exiting Database Edit mode34015 Node: Undoing changes to a field34362 Node: Moving from record to record35312 Node: Moving from field to field35677 Node: Movement within a field36387 Node: Editing a field37330 Node: Getting help37862 Node: Searching38238 Node: Sorting42647 Node: Sort interface43077 Node: Sorting functions48638 Node: Database Summary mode50520 Node: Marking and hiding53410 Node: Setting the mark and hide bits55545 Node: Movement among marked and hidden records58624 Node: Details of hiding59968 Node: Reports61443 Node: Specifying the display format62722 Node: Changing display formats63541 Node: Execution of format file eval expressions66983 Node: Making additional data display buffers69974 Node: Specifying control71613 Node: Interpreting control properties73518 Node: Kinds of control property values77060 Node: Control properties reference80343 Node: New control example89492 Node: Ongoing migration91978 Node: Changing control properties at runtime92779 Node: Example control file from scratch94360 Node: Record field types100575 Node: Specifying a record field type103034 Node: Predefined record field types106913 Node: Record field attributes110450 Node: Database file layout114507 Node: Data encoding115857 Node: Internal file layout116486 Node: Internal file layout details116937 Node: edb-1int-to-single119190 Node: Delimited file layout125322 Node: How to specify delimited file layouts126996 Node: Resolving ambiguities131107 Node: Problems with end-of-file newlines134738 Node: Tagged file layout135481 Node: Relational file layout140762 Node: Nonregular file layout143380 Node: Nonregular database example146915 Node: Reading from disk151328 Node: How information is displayed154959 Node: Display specifications157030 Node: Predefined displaytypes160171 Node: Enumeration displaytypes167005 Node: Defining new displaytypes170233 Node: Display specification optional parameters171564 Node: Customization179286 Node: Auxiliary files179529 Node: Hooks and customization functions183619 Node: Read hooks184658 Node: Database mode hooks186177 Node: Record display hooks187354 Node: Edit mode hooks189887 Node: Display format change hooks192190 Node: Global variables197566 Node: Database representation198338 Node: Mapping over the database199491 Node: Manipulating records200985 Node: Naming conventions204801 Node: In case of trouble208218 Node: Function Index209928 Node: Variable Index225208 Node: Concept Index232455  End Tag Table edb-1.31/doc/refcard.ps0000644000175000017500000032750111016452257013116 0ustar ttnttn%!PS-Adobe-2.0 %%Creator: dvips(k) 5.95a Copyright 2005 Radical Eye Software %%Title: refcard.dvi %%Pages: 1 %%PageOrder: Ascend %%Orientation: Landscape %%BoundingBox: 0 0 595 842 %%DocumentFonts: CMCSC10 CMR10 CMR9 CMSY9 CMBX12 CMTT9 CMTI9 CMMI9 CMR5 %%DocumentPaperSizes: a4 %%EndComments %DVIPSWebPage: (www.radicaleye.com) %DVIPSCommandLine: dvips -t landscape refcard.dvi %DVIPSParameters: dpi=600 %DVIPSSource: TeX output 2008.05.26:0811 %%BeginProcSet: tex.pro 0 0 %! /TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin /FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array /BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get }B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr 1 add N}if}B/CharBuilder{save 3 1 roll S A/base get 2 index get S /BitMaps get S get/Cd X pop/ctr 0 N Cdx 0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx sub Cy .1 sub]{Ci}imagemask restore}B/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put }if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X 1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N /p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ /Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) (LaserWriter 16/600)]{A length product length le{A length product exch 0 exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end %%EndProcSet %%BeginProcSet: texps.pro 0 0 %! TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2 index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]FontType 0 ne{/Metrics exch def dict begin Encoding{exch dup type/integertype ne{ pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def}ifelse}forall Metrics/Metrics currentdict end def}{{1 index type /nametype eq{exit}if exch pop}loop}ifelse[2 index currentdict end definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{dup sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1 roll mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def dup[ exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}if} forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}def end %%EndProcSet %%BeginFont: CMR5 %!PS-AdobeFont-1.1: CMR5 1.00B %%CreationDate: 1992 Feb 19 19:55:02 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00B) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR5) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMR5 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 70 /F put dup 80 /P put dup 83 /S put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put readonly def /FontBBox{-341 -250 1304 965}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4 87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F D1F017CE45884D76EF2CB9BC5821FD25365DDEA1F9B0FF4CFF25B8E64D0747A3 7CAD14E0DBA3E3CA95F10F24B7D5D75451845F1FB7221D7794A860756CFBB3E7 704A52A22448C34812C3DBEDD41892577AABA7D555E9298C1A0F7DA638078167 F56E29672683C51CF1C003764A8E7AD9D8ADE77B4983F56FE2D12723AAD8BF36 682CFBB71B1D12210144D39DD841A971F71DB82AC6CD815987CDCF29ABC3CC96 5EEBD5D661F452C6E0C74F9ED8D0C5B3755551A172E0FE31EA02344176E32666 14B6853A1C303A5E818C2E455A6CF8FC9A66DC6E279101D61C523BD9DB8EB82F EAF4D7FDF6372383C0794C4568D079648689A199D4B65BA646CF95B7647E4BEC 83856C27A8EF177B3A686EDA6354FE9573E123C12EC4BA56A7E8BFB8F9B75147 9DD79A743968F36F7D0D479FA610F0816E6267E5CE327686A5485AB72201525C FB3B7CA10E1BF26E44C24E1696CB089CB0055BD692C89B237CF269F77A31DC81 0F4B75C8400ABCFDCEC6443CD0E81871CD71AA3064ABDE882C4C52322C27FA8B 41C689F827FB0F8AAF8022CF3C1F41C0B45601190C1328831857CBF9B1E7D1AA 246117E56D6B7938488055F4E63E2A1C8D57C17D213729C68349FEC2C3466F41 171E00413D39DF1F67BC15912F30775AFDF7FB3312587E20A68CF77AD3906040 842D63C45E19278622DD228C18ABDD024DD9613CDC0B109095DB0ADC3A3C0CB5 AB597D490189EA81239E39202CBC7A829EB9B313A8F962F7879D374ADF529BD0 5533EF977142F647AD2F5975BA7E340419116099B19ACCCC37C5512589197A52 ADBF6C306800B7051D704700015485D918CFCBA7014612003ED67075EC70EEEC B645B59FB5734F0D8FA5D56BC7FD608751E06FE577AA0B4AFCD7325BD04EA27D 726598E849303F4B9CD1DD27DC5AAC044510F86A1FC54BD6918186134854ADAD 8EC2509939D45E62A842C1BEDD87646711C789CE57100797203C7C866B7A9AE7 BC9F2C4672CE11AF742676915C8F980FCCBBDDE0BA2BB52A81CA8DDE74E7F89D D66102334AFA2E733CCED6744B01E538C7DEE0DD506F6ECDBB5D8BAC10FC885A 967E31FD165FA93E492D62A39314005002F8AD654A6EADA7C60EC6937B7D5A72 AAA60633895B0AF968AB85F3D4D1A0B763CD2C8E3A400763E6D342172CF2B115 463C501845D939713E43336F9BF4C93DDB21103994CA4B11CC4D87CA902D2406 CDBD98204C370B04CCF55D07C80537A06A03588DB862ADF9DA73198E1A612627 04C47846971915367285765262E5F5398D858FC8A283648EE9E40B45EBB33AB7 E77B842C4709DAFBE1F336A9391FEF347E30470F2FDC9FB3ECF75B263C21ACF6 36C05D5EFF3418FC7ADE9833165C02443F2EA8ECFD94B1D82EF1A43CD6CE6B51 B672261030A7E1F08E63ADFC394A8743AB1ED3696EC48D0E1EC962C7FD0E33A5 35824CE63B7160FA161CE25030F050B6D589F97D6F9E96CF2038EE3F2FF647C1 993E5637CF9A4B698C4932C6D7E370D0A29C60ABDE6F869252A13B903965D5A9 73DC4FDB31CB53F54C4DA268799B921ECB563D2F289C86C95C5A2D917EE6FAC4 4F40FE99EC326B6A9E0BD7C314C36D008FAB7CFCB16927B708C67DE86F7CFCA1 19CF798DC248C391FD0EDEE89D10AA3A6E6361AD1B934DDF33651DAACCACB61D ECCC30B3C40CD24D376C995021419EBA3122DDD14210D87F510C7757B70503E3 BC462054763BFEB88E640FDBD4951DCB8A0401AF8FA317536DBC4FA3DC3FFC83 5FCC471F745649619782D1420623F1C7C016DE9EC5C882E5DA167C4DF0E1E017 ACA8347F5F4FA34DD9BF523E7ADDA50918A7A29C8A661F6298F2C6E2DA668AA3 806B7B6EC856CE37FC45EA077CE0771E719E174B744101FCA11BA8980990342F B6EFE5C0F0742AE5431F69F1F5E75F3E4F227AB6CCF6E643B60EDCD205A080E1 291CE1F0AB273ECB66F227A7566716DB155CD4A464CDE6EBE62837D69324EC50 07F96B479145C7F78B9ABA532E7C848BE24238EDE9DF5CA0488333B6B4EACF78 23293798BE3C732FA51E13A00E463ECA9EEDA4FD6844E594FDF46FBB8389ABBD DA7EFC3C86AEA3C0425ACAB38D85100CED96D2FFBFC3C2D78BE1D7C9CED8677F 1D97A19D958E5617AEE85792376F469641471DD0A2078ADD99BDBCEF949CC1AF 47C9CEC45D4984CBB6BC020B8FA1EBB854CFE402173A706196E30A229A037F7D 8BBDBD40B2EA4D4CCC7967C99E6730B80BB044B2574EE46AE6F0186495E81382 5D1D6E110137868207E88D6DCB5D93E251E4EC17B72C7EF06F67A3D126FDB0D2 7C5FEAACA1F17B3F015C3FF8D990B1CEC457BF641FE8DC47D5CD77B8E1321F10 B8908D11829DEB650E70A3AA061950BAA1CEB20F1983A8416DD82FF7573A56E0 2D3E76E74FB0CCE1AD330E2EBDF13380CE2B51A8EC859B03CAD29286DD3D9EB3 0847BFED1A1AC4C2FDF0B5178BE5A97D17D9EFE0F94049ECECEB0D7097001FA1 F00BFCAA887186FAEF323FD4943B573AD9A840A97AA28F9621EB1016B9FCE584 012217BE6721EA940ECC7B835D915EBB524029C1EA8FC15074C654620E4D7DB3 154F9D6E9923501228321772FD3AE9FD38A2CEE8513A2AB93AC2E40BD7B11216 01E8B72300A826A54E7F3D8B22D6EA083DC9D71A63519072FF90595DCD564675 ADC308BEF18D41B5A3FB204AD3E3FD7F52CF2E0A693D3C285FE4EF064C4EB1EF 7AFF2AE3B4F0712623151B83E42C574778CF8BF54723738E7CCE5052C23D76F1 4F3438511D220BBB4EF6A02D2CF52BDF815DE2DF52F3F4199F8F5DA0EB918CDD E143C92D5370193BC82C3E08086A3CA049E727FB271430D3E1093CA61F6FE627 A0C53A9DB78383BB33D56C6D66D094D1D15ABF58B04FCC79F141659CC945EA0E AC2E4E1928316AD2181D731868DF6703F63948A925F9793C4AF9F00CDC533E18 5452E7DE5228AE8D09179A499FB23B63C87739556B17D416E7859BD38E205C94 C18B22C883C0C5E1BFA6EE9572AFC4B66006C20D65579783375F24FDC66C789D BDC16E01508079AC1FF3FC58478C93967B53C5A359D5348753040186B43366B2 3D7DF19D927C9192362E157BEA6C1FB158DEA1E2A40F1F3316B56BFEEB81D8A1 E2961610C68C2E9B4A540AC93E0EC5C0AEA600F272BB56C56A4E5D7EF4D7D54F 9206413342E7549750D16EE71FECF2A6ECE6F75B20474D878C39C2C707E83C89 7BDF7329FBD971CCCF02406C6913F959305BE504D9E8F066D226A6E80B448229 62952BAA8B2A5BE9A78A77F484A81A8D0EA02655B80CC2EDC0AB5A746E122E67 733A772D65AA4D7432402BE24DFDC9CEAD38FDA96EB2EED0568E9263542EBD59 35F9288631E16AA77C2D517010C12503011B957BD031A965531C75D1B7912DF9 F67AB9B756E437A25C5F2B09D25775647263BAC1ACADF72196B7E3402C940F23 30B8506F5CFE1719C21CDFCD1EDB8882C7EF5352878A8A0427A21F5FE4A90D3B FFBBDAB1E56A1735265BCFA7B37D20A76DF8F6FBF65D8F0B716589E0ABA662B5 BCED3620D449D85D24E3C3F1CDD81F3C3182CD66DEB4DCB00AEBEE548750B454 B365FFF900145EA311886B7C9245A0DB2D843431986D0464E277F12327F00338 5E5835B20610E160194AE1F4319C0EDD26D39C6F4CB8F70359CC99451E70AD73 63100E1DC363EEC6B9EBEF33AF7721333824668BB0C60A1B4306C6569E5BEB39 1C0B456D7D2D330E17BF904C860FCD6E74C3CF5530A6C4BBB72A39AA36B4A8C4 D62BA12D8F2151FD51AE0F1EA03D069A3094AD85544AB77D6FA4A202AA23FB22 2CEE232C7420B1CF85D7426558CFD488C4B6BF6B44167D8FE7A28F36506B7EEF 54B92D88D3C950ADD403178341E363C27643DD5B35047D00216D8858AB638312 4EFAD784D8BB6EA8B336AD77CCD6EBD1EE3F2629B6D49DC8B79DFDB1931DE97A C382B99DC8DDC7D4672E64EE8AAB4BDC4DD03DBD5885520C16422EE748422C81 7B2DB4C594D242210827096B09F1AD21B37CEE8E4E16A2EBA065A5584EA4160D 0A43C51389E8064225993E91803506778722572AC3201C078CCD4B62A3C56AA1 BD47F7EEDFE2937A7991F98EA499CF3AA91C7FFEE8345951BD370A47D055A19C 5D13B78889A6AEFD2B76F6C8A0CEF56F045AB849AA9D9E3CC8BCAFFECE2E03E1 C028174920A3D6D713643C68109134F54C688F07840F40714518B5DD3F4DE0A5 2525C4E2AD658EA9862B4A3BD38F367836BF9710D79EB4110C0987C801FCB453 993745DC184BFD1F793BABC1F90BB4A367C9E8AFB4AA19B6541EB0E9F3FA7644 D1175EEB8536E7E4DE3595F58305D79B83B5E3934D02A8D6F33B975161CBDDCF 426CFD8EB41A2D9793B6FDD21905F8EBDC4B3A80ACF2D652EB20242D67EDCE00 83FFD907B4A9F159F5E1A380EE08226963849473EDA6BE89FCCC70F28778EBAD 18F1F67987EEC3AF924E4086FB36AF2A3C81FE5B86F8AC55A18F38B677527AC8 56F7C392D84EB461C6C125E75DD04193CCE93AF394C05D3E1019CE8FC823B7CE CFEE4CC63D4F053067FE331AFD3370F898108EA8B0B0B88642E6606231062A4F 89546371D4B79C277EA509E37E66399746C3821A3AA6013EE389B8DF269322D4 296C0CD86E8BDB2B10DC66BE00822DD610CBC488A5EBE4DD2E7E83ABC64BAEE7 33F0BC40E47F0D1B82DBC1BE577B8B878771384012A8B854744415F70DE7D30A 4B52C5048DAB3E200D0561D21957AACE074A2AD9B6013C4B4017102683AB724F D5141046EEF26FF28DDABD08B6735BF8271A39419F7F8478D9F6DCBA0D6F1B9B ED9FD169BCB73EDE46DC63066973FE248DE98CFEBA68D896D2EF43ED6DF433A1 DC4062F56D14E10408E5B2786C04021A33A35B573CAA72AE7795D34A7BCFE0E9 E683C6E495B18A9623A01C041C40BA424EB6635B153E5BABBC5A670E7153CB65 A1653DC7C47D2D239A31E904C80E2477CB9B378789EF82985AD0495E035828D9 684FC09F0171A6FBF114C3779BBDF68251606F2BD890D89136A90A69956645B8 F7A384F98528CE43568A3E747C3E7524EAEACDB16EC9B8849A9CD7AF44CE66D4 979B6F103858CAB43AF5571747A4DCF24ED70C81993CC5FA0CE274BC10B4D1CA C2AC239AC4E7A1FA8F957F3D87F3F4A97AC1C50ED11C965531ED48E6316F5FA8 059707A2DCE945149B3756E83710C3AB27A5C10F741E50F398F84A9A71FC4B27 D0B2163B5DC55255CA9654C31F8AA119730B2E5AFBDF04F96E64D726AE8A289E 75857578920374BE2706285D4CDFB9CB5B9E9305130F1151FB6843F8653764B4 48296CCAB184C522CAE08D0A68903247EFC8F39AB50AF8C9B7A21FEC2F9DB2E7 4B618AC14162F2BFFCCCEF945DF9EF51D7F647A185D63264C50B09B439058682 C1C9AD823302E46F82E7521FF5364EB01263F68F99E94301129CE3B80D66F26F 803F8F0572C335150CEEE6EFA9D01AC80009318A748C761CDE5504C12FCC5AFA EF3546F10DC3CDF3A328B491B20A24B37CA0E594A5E217DB15B813A936B3CCF2 D378418986D82F4DA63FCCBA7542042D34EDBE36D42EA648E789E6561868AA0F 7543ACBCCCCF18541CA5EC47E2A693EA70BA32785548F00AB2470B686F409E72 CB14869EB92253972B8392C045A2D5BE28614B2C324E5880437DF6A75577FD7E 99E831EF4736AABE3DDB0B8772C981EF0AECC8F59623A245DB70642D781259E7 6C97093E5E7363F50681642E2FC1F054D32E1179E61DD34C152950977C4AD8C6 953A32B76FD21E6ED310D510FB73E8B7281259D0DFDF57AD24592A09D09690D1 681668D6C50E6C95C3C4A658BB60AD2425F378687A3D8ADAF0CC83F23970CD23 7B46E8BEE04C22316ABFDE9C87E84FD7C757FC9913E5159D0473FE92B43D8B06 3C0593C67E9D09AE3F35F17BB196694C653637DE17CB5DD240330C89589291A0 10841B6C9B044493642217693F4863B165C6EF5FC3B43066B7EA902DA316F54F 1B82691E4E1B8DD2A55DF310FD3C70805AAC118D082238A22CEA39211700BBE0 4B4BAA33E30A0ACC038F630C6EA3DFBD90605222B7537243241AFBBF979F8518 B2D6B0FA8981C0D479288E8E86225B9E6546C8B1D0AB4DA5B0905A8B647604E2 4C0B23B6473853D48B3D5263F4245446C4332520F5D243A7A1960B28AAAF2D3E 1B716538CE78325F85452C6819D030EBC5C7FD5C9C39AC200E6ADA4AEA3F7929 6C492C38685CD67E1641D922AAE32CEA85403B3547A7BEB6A9AC9669E451D7C9 1104E5E1DF8DE39D3171D4E491C0127FAC310910F0F98E7D432D8BF7E89B1DB7 6CB88A5F6965CDAD48EE66C26912ED9C5462689ECEA0DD2AF8FD0A5A47283444 FDCFE8177B863005C7206647BF0214B84FEBEBC492B6351CD0E1831626D0BA2F B89BE2F3D5CA26F21D88042EE6E15001AB9BC0F55FF1D8EF1F8D385800B872B6 504F117475390AE5DC6C55EB8322CB1FFD9F31658C372462F812819B7985D545 CC83C05B19F7E050A459DFF09D2C79D65971D47D328056C446E809A1C88D8C89 E645CFCF78F496FB8F6BEDDD41C0FDDEB38A6EFE81048F0807872D682532A530 48EE3D92F097213724DC16AD7528A4106E4834B8C23B2F495899FDB74A810260 945FABB25BEFE0F78EA2BE3B96CE81A0E2A0FC7DF1E9CE04B308E499AC6796B2 20647AEC2EC01ABCC9C9784199977056282B07F66D760098B3CF59C22E413544 4F0F1EC6EF1F9739218CA5C8344D412DB267B5716943A8399AC348C441488F3F 6A7A9FF80641BEC69D0CE8570F301B942AE4BC716AC64EA50DA5F77DDF71EB48 FE99F1639095B35CC2319032390344E723442E080373C2FE37BC52A7F2722159 F9022B81565CAFD6A1975965A16B5929078D164633FBBC53E86947B67A2507EB 3E73E17D39C8C0BB30F0FF57D1FBDBC7EB2586311759E86C2F2FFB3045067FEC A6F3F9D64513C2B10FC8286DF9C59142033669B394E03C4D8995996626BD44B0 4ABC87E09716B5BFA4C8B05340D47DC366B4B3A598E3E4124CF67414813057EC 3D456F3243C208113F5A12FA3D52B75E177C3763E7003861F81DCCC06F9C75C2 5867C1D204AB4968823693F2CB6CB6A19000B78768F0562FC842C0B25EC0794A A55EEE29BBD26872D150DDF77405E9E047D14F41A6B45098ED83E2CFD3404AC2 565CB2CF8B11C22B4B636C5B7573C423A617EF3AE0E7C12F0495F446E3458AFB E39111BF8D3EA344F8A23720C6037A6801147546EAE443376CA5CD5056BA3587 CA0489083EA34AEF8E6DA3362F8E400C0E5D7EF5791506AB9B648B2A6135E2D5 8873A4C6A319BBB1BB9B3B25F9DDDDA44753B42CCA5B79B6DEE8EF09D3C8A60C 1AAF9C8712B924AAE84DFF424C26E53E86 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMMI9 %!PS-AdobeFont-1.1: CMMI9 1.100 %%CreationDate: 1996 Jul 23 07:53:55 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI9) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI9 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 78 /N put readonly def /FontBBox{-29 -250 1075 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE 3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B 532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B 986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958 9E394A533A081C36D6F5CA5FED4F9AC9ADE41E04F9FC52E758C9F45A92BED935 86F9CFDB57732045913A6422AD4206418610C81D882EE493DE9523CC1BFE1505 DD1390B19BC1947A01B93BC668BE9B2A0E69A968554239B88C00AF9FBDF09CCD 67D3B2094C11A04762FE8CC1E91D020A28B3C122D24BEAACF82313F4604F2FEF 6E176D730A879BE45DD0D4996EF0247AEB1CA0AB08FF374D99F06D47B36F9554 FAD9A2D3CE451B7791C3709D8A1DDDEFBD840C1B42AB824D5A0DFF0E0F15B0B7 22AEEB877FF489581DA6FA8DA64944555101EB16F7AB0B717E148B7B98D8DBFD 730C52937E226545CF8DC3E07C5BA30739BAFCD0F2B44275A6D503F582C0FB4F 449963D0AD2FAFDE33BA3D77BCA9D1DF878DDAFCA2E22CC4BACD542B282164C7 97C2BDE318AF9D501CA21F6E662E7AAB75A5F24D2C182E598D175D44E88AB19A E7CD59584F95B389183EE21B525BF52A3F23C0FE5383A5565A19361D716F508C AAB78411CA5A4D27552CC1C435760D5A89D535B71C593E755C616661363308DA A683F54ED0C23FB2C225A008392B0B719F66F11A946A090B7C00B662A3C69599 B4ECB0CC70C85C4BBBF207E0026F6C7A19F2ACFB7A60804FC98A4BFFD7BFFF2B 9529E6D9D4238002BBC255BC62959D6F3381FE06E0621B879D5FE5B541D45A1E 759A6E7DC32B1D1632368D09A97039DF255B6492B1B2B7E2C1434E8306ECA7D3 5A79B6D614B4979F10988BC76ED53A5F45315CD7DA216221F842FD0F3E050DD2 BAC23C984D506D8F7D614BCB6B244F5F41321549BB0BD041FBF3053307168680 3435E9C9445A59A7C666418C4F2512C32058B1CE1EA45205D36792B339AF75E1 9A70810243EF3F5F776041BD244A33D027BB076A29090D59D4CAC7883A0F0FAA 4E3ACE2E6383EE2319DD1BE232A716CC775AA376276F433E3FEE07CB6751F6E8 6A77736CE3429091B85CF4BB77180C824D8DB3D8B81E7B7FD2ACB44CC137DE24 28D5FE4BE68B6D7468CA0EB05F34E00187CD26DE3554DD8E73EA400578F79334 B744F3B00BF061FEBA720C30DDA87F54782CB4C017772CEEBB89B65DF93DDBE8 577E8B7D118E501721B2A21E82EFEB495AD7409A7250A4765A2964C3A7888ED7 C1BFCAF5665125B77B86C70F7B360958DDF72CE1C0AF58B171B2718FE0F2C41B FE8F10770FD9CF8854D393A522B87BEC08957D7BF6A77632DA1D61D06673039E EFB2B30519F1F97C82F64BB31833D639A5467C50B3025DC7A3CED7DF355B7755 7AF0E11FFE688D3C2E3672546B21F9800C5C704E5FCC2F386BC4BC9F5CF61952 4ABFB3CEB1A6A4D1DBC8E5EBF9B8607F23582EE78216B0F666CA798965C43DFA DB090DA6AA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMTI9 %!PS-AdobeFont-1.1: CMTI9 1.0 %%CreationDate: 1991 Aug 18 21:08:07 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMTI9) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMTI9 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 13 /fl put dup 15 /ffl put dup 45 /hyphen put dup 91 /bracketleft put dup 93 /bracketright put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 105 /i put dup 107 /k put dup 108 /l put dup 110 /n put dup 111 /o put dup 112 /p put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 120 /x put readonly def /FontBBox{-35 -250 1148 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE 3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B 532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B 986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958 9E3948FFB3DF7BFF10C9BDA4EFE5F68A8CB1526990D1357AE6D2F7C2D2EF8496 4E47B39E6712EB8908A3265E5FAB40567E866C244814449F1E993AAB422C3F1D DFA8C7118584F2E5197FD4BFA3A8AE9E953C6CD4672C0FF51E41C3A919749C1A F06650DF4C5E17492164BDBCDF22609A74BFA7F69960A64B9F949FFC2A807458 8579366C4F41BDE1FDFBCC4845FA19BBB6963D65EE8532549274BAEBDFF24FA6 03235D1BE37C06B1938AF369DA75BF38DDBC87A1FF445EAA16E1895ABE9506B9 211955753E447865D33CEF007391D2666A046277A30A49804FFCED3FEA5EB2C3 E52EE14A9F75241EA10C91974CDA6236EB840FD44D6DDE4D9B3266C3B99BD38B D835BCA8CB819C073480FB972CC028D218F6A1D344CE1B63F4FBF2C826F412E1 6E0B05A26125865A14FD7B7030B478BB8BC6BC395335C3BA940E1C348267F4F9 0AF97BBEE253511940F1048E175D3569F7D05A28851B6F50765FEB6C9654FEDC 1BF52F535DB5BB90C1BD5D2EBF75E0AEBE82B20507F3C28A03746781018D4EB2 298E4F2C27ACF73FA73EBE43F014BB575AAD516C0407B29E1653375135ECB74D C91372F06FA8EF37C31AF3FA48AE65318EAA6C34830A5377ABB2DFA5DA53A574 433484BA1466709A4B186761655C8E482833B697673E847C691079E7F1DCB8D6 1AD91101D757B83E2090337D525AEECB028FB3C9F6A6E6AD2F322CFDC5A833E6 1CE4EDBF41FD34FD61630581D222F854A76C2EA9FD72796A7C9CC1F6C2FCCD16 E95CA05826A4ECFADA6A5FB83C41A7131E52BA6585DD6DD78515D8F7327DFC6F 9404F89286178E345A61E157D81CFE851490E27B74BBAE9D7F7B534D6B2251BA 77BD99DF43E5B424AC3A8B333E19F1F412DE516C61F81A04AE56F90F91512C5D C2014474F53F7FFA16D9382A14C2EF3623C2DCB46E5B647B9D4EFD3DBA7E848F 240F7A102105A67AA5C070FB147DA6274F9674CB89D432E5E21EC4202BCA4FD7 692DC3659D7516F7589CF3946FD7F50A96B3E459F3319B40C36B5010B660258F 730E9D18F18E8076A06A88A164F719BEB5E1C9C717BC5E11B8ACEAA979823CEB 940C2CBC1DCCB592B3770997C1A5DDC722FF0B951601961D27BE038F0C9ACD69 33E78883D0149CB3EFA436BB405A3DD3018D998F55F7D36D7A7288E9223DCECC 17AC788D75EFD77783F235715A419D963ACBA1ACEBF0668A51D3A16DBD13AC8E AF9183CEF9D25BE9CFAB56E85B2BCBC26C9827EBB0FE323644001E599FC7A37F BB35D08E01F2533ECBC87E22C655A9ADE8D746DE294978B39C624F26E9D2AF28 7DCC9322F05856841CC4674D8B607D558DCB8CF3B184EC919CB6517965D3900C 9F8BD53BEBF48AB6C7DD4A8F0C9BC7D8CD187CF3C589967948B4833AD2CDEE68 C969A3BE53493691BF10A19537F6D2D04C372DBD43CC3366A61D9EB56CDC29F1 6AEFD6554CE609E5D53A77F7F2791153A6DE7CEE0F923A3597C86EF773611C8A 9C31C2138CA289F6D93131DC689665E5C41D8ED93E07F627E9731CE99E19974C 4D3ABA1C52F9E0642A4EF114ED8BFED63D542E0BE9D34CE941B8A203EFB587BF AE7633A1E2659DAA6C32C814DD0E5F511DD997BCA9E8BF39432B992FE03D6EEB D0BB1951CB9FA29ACF91B4815D5D7C7605CA77B8FF3B4FE6E003955A17487BF5 0E22B60EE71352B813E283BABC1898D3EB2AF92B7FF33B5AD4AD82BD706E0BA9 2BBF69B74FEB40B0F2863A9352673FEC779BE052A04220305F127F9B9E7BBEA2 944163631F562A1CE9C6E2B0392FA9A7D18BCA585EBA45B454BEDB076E2FC6BC 3EB6C931005304C6D09FEE36D338874F0807A4AB52CAD6E6BF837DE680E23278 4AD7796516CCB614546F50A45B255F84493C817F5965D3629B1BF9A0A513C277 09905A49D06D98E770649463455D888CCC2788A05A991648B4CD47792CEEE5FE AF9A95ACC6A52586A06278FE45DB03F95E4EF6424683FA678323C0C8BA1E34BE 67F3242ECEA4317DFC29171F55B0A17D5F028D2DE803843FC2FA78C2FD87C93E BD2CF041A8CDD311511ED33D19D33FF831D2F764DDA149804E9AA5B4ED8090EF ADD68265993F407CDD8D20B39D808808CB3EA547AD0F05A87E803A441049D58B DC91DEFE56502B233C3B9BE251965F9D440C119FDE504D90B7831B7F6A390A5B CAFFF396899097B83B553F75965AA972992C06FDC4B1BCC8D0022B379AB75C0D 06FFBAC1B8C1D06D788B760FC455931455ABBEB9954DCF6EE9785D55BE9D5066 F9B02E6D1432500BF6609E729D95EEDE73847474B332397BE49B7F4EF5666ABA 0D2CDC0ED4D2378EEDA2C2F7F99D8234CB75A4130B8BEAAD3970F6A1FF65A334 3D612D254DEF781F211A716C443B043D2978D2BFB5C1EBE510A6B2B942BFF428 54F032AE2F6D2FD07E4F90AFD6E1A7E16A21DACCC05640CE8E95B9DE4C3BBAAB 41CA256D66AF751126ACD83303464C1A8FA2D6EFF69BF66F7611678C042D7E3B 2900F175DB1309DF929EF115BBCA9208BF8BF383F3E9F82E7D072845E43DDFF7 D74A0D0C2C93252F5017356EC1A8BFFBC41C88701E0D0F022B22B179F4002C70 9FE394E4B0C385343A72FD59C3B36324825E3898B056DBE041C4C9F00EADF1E9 7CED272D17BC711DD8B28FC70440B76104B4EBC87F853E676FF030C688727F4A 2E2A08E20697583121F2546CA1EE3C0E14401BBD0EC6305F0671378DF0940BBD 893DD14D7F045A5EB0CD6978B9722742945A53F4624E04B500330FC3137EDB2D A9FD471BC3039923659E3F011FA4035A2C2627261457E302486FAA323F454B70 91FA7601A97E4C35C26BF03F5546E4831F26E1F6F39FB05AD8959A9992964216 CC80A217C5BF449CCB0213AFBDB388112CAEBAE34772F7BA6FE2A8668E077777 2B3256CC1CE9258DE7583595843AA4A354CA56E3492E255CB39EAA25F99322DC 3A9A2C679A0902BF4F885D907B8E87539F1662D339F55D7AD8EE81C353E09E83 4F293176D49399F04FB98CA658E601B0C8B797B7CFEC4AA2850FEF8E405E3875 1E8268A0A0BD9848BB98008988331D6CBC5ABF7849C3681F68220D7509A9DFC0 5C37D5E5F42EC0E70F5644DC29C0921D6FC86E0D4D0966A75E8255BAA5766E52 386831606F9F24FF37D439BEA84E948D970D47C45D0ADBB106432C2308D7DE9C AD00B0CD55DB37D3ABB1499FA71275392678FE10228E1EF0515F7A0AB458DBC2 78F9279ABC6C612BBE52050B0D9726F98F751F038506E8373022F3411BCE41EC 4923BA81E80AD9072C4E355CBB92046651BD61AC508B147F0CBC30888BC683DE 0065EC2846D053091C5E14A873CCE7744CDD03466594C8908F200E0428D43C6C B3BE45A45944D813E1D96AB6AB5B5B58042AB306D7A0A37882365FC2D6F34C89 4B136998CAEF486ADC68A8D76D86E7373C25312B5FAE1DB2470D6CC890BFBC10 BCD790EE4A078627BCB80C46D9E742FABB9578C4AAA99B7FF03239278D57980D 48F1513FE7AD60280886BF01AE71899EE0E00590649C4AB3514DB5960C8FCCCA AFB01F052E98D70D6AB21F20CBE4F7CE0BA23B1B235F4AA07D82A8156231F3F4 A5198AA02414E2D1AF2D2898B2BBF0FFB391E3D70C75895736422E4FE977752E F73B7D9C73F692ABE93338E9710D75659EAE105D0D7E2F20103297756FA6C82E 9A5E819A294FEB6A9D3D8D8E2FE604F1D1BE4FA1C516E7E15BB5A831573A7E0C 7DB3DCC88C40317F2481003C093FC83C335BB35BD66A5E991D2FC8AE06807D2B 18435DD1A6D3E641E37B85E8D48906B08646FD6D17E680953C556E2B576E0970 EE28328FEABD1567C3C14E60BFE54816A20BF0751AF7EBD6A7B92A024F539654 62E2C935BE092C174DBB64B5670FBB2DAA4001B1A77E8BD1853AF03E86EB2132 4CDA80444594A4FE079EFCE85CD3BDFA4A9F675D71642E4DBFF3ED5BC5D83E68 BE8979DFF1E84E8A4502A61DC03D4579ECFA27D332F453214B02E361BFDEAD5B AAC393FF0E8A2575C042F78755F86D2A3EC0EC6367012555DE6BF53C013111FC EEB953279D85A20212E2842980DED700EE8AE1E451AF4F1A5873974DEB3FD7DA 5B3FC677D3FBBD1F0A3BB00EE75B14535A8435CA9391AAC923216E0C1AD8BC82 4DC2E6FCE8E27A1752199F2E24D41E5CF05398E1E109E5D626D43A8BEEDCDB9D D4C305C4C7586F1483D241C223C8149986BEC600A2D0137F0A6CF13F5CE4BBE7 C3CAA3F41F0E6EF903BABECC5A75CB2FC69D919B39251178F5F72EF9D4A9B7DC 6DEFA1560A0C3CE7A3DA68195259DADD67842CDB0548C270B4054CEF60157836 87DFF85C96535C24198437B2AD70F33FD647E059DCDDE5C45EAECA9B534A6AC3 D5994EF64039B955CF8FFE2B4198D5F39466915D045BB931CCECF5CB5B6AD388 C2EC740C9054C3D30EB10025CCCEA5B58F4EF59BA80AB65058981827ABB00C7E C5139A8BA7485633673D722FB8BA74F394132C509B629D4CD1FF9981753EED1A DFCA8E05C0A1B8EEDB696D6B1693CFA874CED15A70D32757698BC6A1056D4E17 4EECAA96B1853AABE6507C5EFC619A61797F745FA66FA37665CDBE244EE58587 3E130ABF813BD7685045B7D8E67DFEE0DE8540D0403098BE9C74A0A846C1BC0A 367EACCDD0FF8BD23DF40C30C7F9D34B4091FCBEC4B2307FC825471331D5E62D DC95EF28138D4719A331DE91C466F50B68AD81582D2094762DA391BA52FCC864 AEF2E7E375D1451A75039F1ABA4CBD52A2BCB67C0184EA4040C0005431EA6E20 BF8D38224653EFBC3790934F62928863053C314EF1934AAD59BE6C43FEF43839 5D6E64CB0D62216400A1FCA7CE9A5AC2B41D526DFDF662C74EC9A70F5960B4EB FF3365B7599E94FD937E6F156970A6EBD96AF045C596AE89D6833C9A7DDA1EFC 1E71841D8C314951A8CC21C59EB59B3FAD74D95270A65BA11C4F9DA3545AAF41 8399B6E79DABC0E5FF0C50E3C6C415EA3FAFEC20FFFBA6621F3E1DFCD8A7130B 80BEBADB6AEC195E8DF0659740B8E2F9E8D78F3002B4BABD2A85478B67836EF4 4CB4982183DEF489282BF3E7F211CC4EA7AFE3F7A6D9461115152D66D8BED8EE 828C53C77981A44D8B7A385BE7AE4BCC9EFBB127C9CCB929840F890ED747E3B6 B4AF69AC8A98FACB3346A4D2D9F32D1237658DCE99E45BAE0645E447C3931D9F B92D51128F95F7AD4E22BD2AB18665A10CBA4F1E60F46AA1A114E758F19DE6B1 84E0B0B5DA86CBC07BA60176DD367E41095099554921B7A8D7A60A52718F5382 96A1D903B72653BE9F1EAAC4717C0D93F1F47F93BD8D62543C2F6F0A84091B18 F1B2E415BD9BB97B23D1377F751BB1CF333AC6500076D93F05C9E34C960ACA01 54489A0148FD539AA1956E9BBC8366C7B4382AEDA7BD8A979BF480E0813CFF55 33D8EC15BFFA1610D68E148BF5C811F5297630B676C264F2F1F08598DFDAEE78 708B20054C3E514FAB8D79BA5976B895E150005184592804D3C69F2D90866246 BFFA9B24E33E983FAB3E28FF36B45C278FC5ACE0B5F054CD79E04C5BBE1D3692 AD04AA44EFEE804E5F7E4439BD3B0943BBEF32D76B673DBA57CD0884695864D6 A96404A2AA6C42758974656AA4E0901F298D47C1655951F00EF809C7CF2C7603 F91D94B3B9B38BF9E1BB0301BD39F6A685495B33FB57DDF3D589D7DD04B280A1 A84C471EA28C84424A82A8890D529E39ACA548DB0CE15A8FBC49C8430BE1A11B CD2391E86BB872484726B604C71D08D2B8EDE2D9B1F8380F95EF8AD3F580120A 2CD629879860EBFA8BCD7937D716196DD5BA9CD333D3D605DE26C02EBD479C7A FF2834068319B082561ADABACB78D0FDFA9ECA156980C415567C6BADE0DEDC53 AA8EB6A7C361A324BCB960825B429897ABACF124F5365B88AC1379FB9D2F279A 62ADD20FD668DA414F95BEF4C28F4A8AA89E6E9FE5819FEFEF6DC92310FE3C77 D34E7AFCE308EAFC99C0A919FC592AA3102BE654858FBD4F9944DE81AE81723E 2D5AE2DBE27248869156552401CC464DBEC82D7485C7384328D6034B82BF5B5A F281D391E9DE8F7FE6478949DD504B70913EAFB795787080618E6578DA12F290 FBEA1F32B3CBE594932AEFBFB8CF7C6F3448A1CB576335982745B430669F863A 91A1FAA7714B85897B9245981E00F6BFCB9F98E28F699E2EABBDD624A56BEDFE C4BAC2C637CF09897DB72D5BE9224C9288F5312A4F2693376AD49D4B4C353CF3 0F974B672A0B1008C600AB431BFBECF3D687CE35DEFD15F023EEBECC15E1BCAD B9E92E560071513F0C24F9BA0ECCE72B07A4C2E9C198F9E36238EE3B65FCFCBC 4DF8D5ADB61BEC75F7079110BFEB3928885AB2E1D800A9FFD94FFBFEEEDB45B3 71F1A8BF1131B39BC41B93A2329835256C9D29842F11B910ED2155C272CF7806 E308E666B2743FB9D8DB07E032B8C7E9CD309BFC16E666DDD06E93267B9FB50A B11A3FFB57431966CC13D22B66A8069ABF7D463FE8887D7481E2B706896019FB C18E48070916C9A0D4D3B04EB23DB000D82189584D54CD9D827151DA3F7E7CCE 5A6231907D59203EB5B83FB6D5BC586D096AB9D0D48E7645D0097EEC1B10F780 25FD235E5F8CB4E8CFB6D4F441CCC17734FBD5DE51B9AD14AED0C5127F195D14 217F13E832BDF0374F04B111FB3D90420CD8C8DAFFDCFB4D91EE27652148D46D 8FEB8FF97013551BD217463C609E815E29AD1E259B2E5866EE2053C87D7ED163 71C076DC9E7D4E9713F1C55DEEF73D2ACAE473A90CD7E8041A3E30855488E257 E934BBE8474E288E28CB431738CE61954AD2DADF5A8CBD622E96C61C8129286B B10E6D81160D57EB6736BC6EA6AB17F8EA023905FE4D00673E02AC542B56190C BD8E50B9842785E6D9C9E7EA620F4B4881BA49F5B65CEB8DADAC31825F8104A7 FF19E3A21D9FA9192338207B3597A642F4E7A19A1C423D104E00032BD7C2210D 3D389ED8E61635383C8A96CD4CCB850BFD092F307744B82A0ACC07D74898725E 3C98775146DCE16CD715EBD385C7ECAB6C99B716F5DEC5EF2496D58616341E52 885FC4ECBDF9C23A7A0BE35B6D4F93645F8BEA699BFA55ADC70EA5B6DD7EA9DF 195A50A04D504E897D3C9421E22BF3B7FCF66B39EC9E9484E7C60EA25EA7A3BF C4C5E0CEAEFEBF5842E94DCBD2AB95D9F8952F8BD03204C46C7C5A9CB9919C63 DE5F650CB096D22FBF98DA7B7821FB208329ABD7B2DFE76CA23CF7913210EE34 7059BD74421BD8C1305BFDD7BE44A0DB244EEFCA0FA105AD8139F504FFC3460D 07DD391C6767529C461227A8ED31797BD27406DDE7EEF79D963005A8A4FD07D0 2029FBE515862BB87682B3EA65E72B884BBDDAD41BB8EFDE00C17380868854A1 B79C6B712FC6B29AA02402CBBC47EE68399458F6459476ABAFCDBFF780B820B7 64C99D45528B06299F3F659411D068ECB6A3FBDA042F49044A494A018EF5B9FC 62C9EE790AEFF672657DD8A1316CE89146A0B2A0907A6D2526FE78FD5F113F98 024978693F82D14F9ED16A5D8DB33A5251F4977B6C91D0968FA981530CFB3F8D 16A14E74CFF31010183A7BC4609524C850DD1028C7F8D3C21E11BB5B872AA699 96050027CDAE92D48C974134771881A92DAD5B4341DC80269825238DED99D657 D7D1D0BA0A03C34053 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMTT9 %!PS-AdobeFont-1.1: CMTT9 1.0 %%CreationDate: 1991 Aug 20 16:46:24 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMTT9) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch true def end readonly def /FontName /CMTT9 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 33 /exclam put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 58 /colon put dup 60 /less put dup 61 /equal put dup 62 /greater put dup 63 /question put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 72 /H put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put readonly def /FontBBox{-6 -233 542 698}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 2BDBF16FBC7512FAA308A093FE5F00F963068B8232429ED8B7CF6A3D879A2D1E 2931CE5F5D18C658602059F07BE66E6EFC9239D7AB2FB8A4CBD41675B8ECF279 650C29E53B14AC0E392A664848C1844B1CECBB2D5CFB72D0916B675C9A9A1E35 F12696A6F628473C604A95376468E06E295AD6F76CEB939D94113532050B9D5A D2F41A9EFB9424D986612313B89EFE9C8A71313340B248F6853B1EDBF02B7F9E F447220FE131D7D54CFB8AA1281DBAEA73E665BACB1F164552CC0CEDB63BD4B1 4A9AE8AC6FA02242DBE8DA46B64B6BFC11762F0784F216FC8B9120D688D1705A 438B14F5E5DEAF2A98408B3B64620DE3732A4DAE6D08D5D97E34C75DAE19EABD BA0796165C1151BCBFB1DF8D29A63A8300DBDB9E3323CB82D0337598B83F4F2B A97CF5196D4D1CEC1EDB8966E548C0D9C194C932319610FB43EA1B86322FE641 AB48770FF13BD475A7267E142388563D1A400419C585B22A9886074687BEDF74 D905BE8EE440BA2ABF28EAB673399B7F129B9729DD5564C681954621903B84BB CAF89AC5ADB2932472DF29ADA2BDBDB4D05F65F28F5F4C529613D61858E0074A 082A852710A62A147C966F2B85B51B0BE85F11D2057C66FDD61F6C5755367980 9F4DE680601D4DA41B46F8D2148450000413C27AA39B586B74B977B25F0FD3C0 4BA1EBFAFDBEC531EA1210365091671CE3C86A6D4BC591C37DCC02570042575A 9D24252D6E01A8603753934D7EA5CAC1BE4E5AD2BA047DE8F3983B23A8A1511F B08D373B69E5076CE4300137B8805EBCC0AAB89BBB312A77835795E3C069322D 42C893A30AD739E2BDD299679B158F7493764F2321E3965141B5ED1C6F4765ED F46D391A646B30C90002B1C461AEE79E5F094CACCA656CEA3DB921CC5205F328 A2C69F817061D6C60B121EEE844CA5008F23DF0AB872BF42A2C9FE9FD1C7F27B 0D76E4CF123D791531D63BF57C058CA70FECA1470E9D7C1DC29CAC1541210A94 D92C325021B4C58BB006574E09EB1BD6D47F2D4ACA878BE5D256A02EEC1BE69C 20FE70259ED6ACF33BEDE4284DA2AAD3E9D4C74014A53295C09935971B02AFBA F02F5885045843454158B916C8EC60D16AC38215DEF7488F8D376E5B7DDBE2F4 120CAE42DB020C07034B96F223760046E7867D41F1D57395534D0DE71E506881 9FD75EF2B655D46E133D98115C5BEFE1BA13686C12E134EFC8B628B131661BBD 980DE47FCA9C60BF2EB8ECEB5088FCF178062066740CE0F665913A8953F44B39 D6EB756CC07CCB1E5057F27FFF4BB97B2A0A0D8A69E57E745F141C352D0E6DE7 F749341911AD030974E19E2E2C77345EE372E2F8E1D1E2E80F9E4C4A29C70B2F 997786036BA89AA7940ED72B3F3E06CE5C17809C085C3E415C0BEDF03B12AF09 C47C9C76BC6B56EF23069F940BB7F76CB037C6925E631F0B146B521DF0E500E0 F32D5478C02F1FD40D0BE98E52464611DE5EB6E0720B91B9A6D174ABC113DD1E E80DD52C76D0962F76E6863889BD0542A9944DF27C88DC38D691D47F98B0CBD6 C5D4BEBE9E450A504341094FD1291D3A931B00C67C602B6C34EA5EC779B7DA6D 1421B4D6CDD23FEA410DBA6ACFEE2825059AF294CA85CD7B7A2BB154BDBF9389 19DA17B6666E3F9D2A0F1E5B63FB7A7CD5D197A39644D45B4BEF3025D4E463BF 881F6E688F36E163EF993967A5D490B8D155754CA0AE69DFE6775B69CB603C0E A29B57843A4FC2E34143B3E7B72E3767D508D0941E0BF87869D575D7D374BE62 2B882D1A129E1FF29B2A969156EF23D93506D6511D15509599C1BC0AE2092AD2 19BDC375E3023B3F23BF80FFAE6F678B6412EE41CD6B7C3DE81A175A536C2FF0 25729FA4B6697FE6ABF9245CF40D7E47053BA04C7EB9C07B3B64BA90A5AC3ADC 8625872167F2A980E22B1A43470F273ABDFD525524174FF5C468BB0703A2707A 8083EE3CE418E340669046A77B04167C3833D2157B19B6D567495D71CBFC9D7C 75BF81272466CDADAE641E59513EDC63645F0D7F09E77FB8C7B0E97A64021321 4735171D99296E9F5892A7B5B57D7B5B3AED7B781D96DC3E87B29BEF26770E98 68A68CE9732D6D553FB75F02994AFAB0C042922B85EF3133D9B5239DA743250B ACD262991CF989A4863241BFB313EBA6C6D4465E2B9BFF1E5A1B298870FD7E6A FAF3481D1A070593440199DC1DB50DABAFEF8307692A6329861DB51DC0B38554 6387D4B3263319AA31F9882AE7F628AFC9AC6BC79DCA2B2C539059043CED7BBD ED56646E0AC69D19C5150A290F7066F3ECF458D0F7F20BDB8739BCDF0666B78B A144E938C1645FD3E0D9CAA59FAF548A4E93EA9C7973091741A87138790AA904 32E53B8A9C7A9D6348EAEAD0E41B0A8061CF1088DF2B00A6A75F9E9FA0A86F02 45C1BF21D665065BCB606038703BC19B971AA584A58B86D896519C51A0D78CB7 14DDCF0A7B4DEC186E34C4BA83C8AB73541AEE55D428018CCBF7FEAEA207B70A 93486E5FECCDF3829514B661442D13A2F3FE610C342548204FF37CCBE5D6B59C 7A18E474C116587EA2B9F1B39BDF523CF35919B8B01C3FF3BC1C081912ABDB71 7A91873A3F82E5601A83DB105ED9501A8DF6EEA8133DA13B89EDDC3FF59FAD4A 7456D7C5791412BAEB3E642AC1F3F702B03EDCA13EF6A270E6E8DD0C6068AA17 1CC49799DD651BE0A0655A245F2889561DCE31F062AD2D36189021B8C0318E40 FAF4417268D7613882CF0302F431C113218812E927E13A31B0EC7B24A854CD5E C52AA1F90BD9A7543A2B64BE07D6E111258847CC37CC80DEFB454636DE38F53C 951713566F9C1C22CAF4F6292C4F49C02ABDC61A38E504D9268590E7EF6A1A9B D59EC1747F1959011E21510D74C50D40405189263C10E6332AC4A5F3E9F9CD30 C518986DC45F6D74458464F67805328F541E656F0504C9534C7E6742AA0AC2B5 6DC98127B75018890E60DD4452C41BB8649B1DC5E9113AB4254BF6DBFE9971E1 183A033BA46AE451A230778B4FA6B1671A1609C4CB6B67434BFC34829A69E2DB 2662E3F4518C8743F4C5E8CBEE7B3B4DE95574BC1A6168C1096A9EA60200C62C 92067470185C5A5C0FDD33EB45D46E40EF934D24A0ABB505B6671B9FA83EBA6B DC42A7EC5B260B14EE616164989BF66AB84F5721EA3F2408C388E87202DA1A46 AB9E0C7479885795DE55FA5F7A4389BF543AC83629BA95772C358E7A8DE7FC46 740D7F05D0B78D3E549EF822672C0533A80D1BD05F3F13F824AD25BE61D1EE8B DB475E80943284C97E27DEAF2F47F7B1F01257A7CB2C7AB1F54A0F7776865C4F 7053DBFE715AFD98BD2C0330907B04FCACBF71789B9BA5C1D93101BA57BD2568 D20C6A69A4C27B0ACF71424D59363C966B3D18D169A9B6EE636529248D34E3C1 75263414DD96D2079ADAFAC864BF35AF8D6D5EB3FD7CC173CD4B35CA0A367462 F3CF0F7F5DCDC3101ED8B36348A609241EB6BD31A2E3475EE7E68332FE3765CB 5E285871E9F83676ABD238E1572DD849710B4D8367E46B288D453522BE1D026E C83637F23B98FFED2970D6B6275295452117FC4F6F0BB730CF4453CEB912EEBB 53C8154C9BC9FBCF6153477BAA243BC06B952FEC4E71C6D12FEA970BBE1E8061 9A2571426AF8C62806D600772DEB6C705488EE4FCED632013365E7F3798D433E 3C8223C34A94B8D1AAFD1FD6B0AD8B9477C9FE5AA256D89C0EB2BE87E7BF1910 1A86BEF92A5857E6FB993630165E7E57C705D47502ED007D88E2074238ED544C 01D5127A3F56DFEC5B2DEC8596665E0BEA3F870116037569F69802883ED980ED C2FEA597A4E4A2747B609B394B7C83EA8D64BEDD5977840CA0571F3B6D34CCF7 7C5D8E23E67458213ED419A224392DF9DC94A771660EE1CCB4C2B635D152006F AEBD4FAC535B813148BC01435AB7E27F9532FB0EDE47CEDA37CBC8FE1718A17F DED0D9A408D7CB083303A4C4D7B3A7AA93C0FD5F1DD727AC02624E442289A656 C95105B15AED05A23564C6EECC5E8DF767F8BA212BB73C43B74ED0934A806ED1 5BCF4B999FC630E792630E623934FC4D59EEC5742E97C9A1E1D5BC59306A72F6 747FAED9FC5FFEFE33893B59A636D7FDD47144A5FC8007A1452DDD7AFB7AEE8F 89807628D5D97F34DB0A2AAC0D0343784762D668338AA4F6BC53CA23978DFD1B DAC388F85FE00BA34F13EA41794AA9E837F95D0738A645C59A5404107DE5D039 6C16C701910957435A4698A88F112458AA8D5FCC7F075D2B6EAFCC662B90FD34 510629D301E7B8131B767193571519337518296EE51D45B77EC4E9AB06D9E3FC 2A6B0F4926CCB9D813334C6B74A40861C4C861C70580E68ABCDD412CA21D8ACD C943C0326181655D543495991D03B1AF07F258775E1BA3FACA7B050969E8F918 EBC28D04A5DC96F00C976AB9E6DF11CB951A8B87051483519E1AAAB91F830333 D4269652B77EB4B699F75674E047B0F33B754D51923518BF4E4D1DF56A8AB508 04F02791E56A42FAB0FA6BD457E6DE7BA98060E71A5BD59EB192D55E26D12F31 684AFB33F6299DBC1CFDCD517C85645181D81C2CD1D04001B48E28C3E47F3078 75C1209004626DF5A1AB4C2B5740F408C1948E43B347091C4433C2C649BFEB60 F660E8EDFAF4A3D3EE1355962CF78B35BE3B0737ED08F38315F39A4EC963BA1C 15337F0DE6540073F5EFDFBBBABBFF03C25D7C8E1239112AA36190D915CC8DAC 110CAEC32286E9A45B32A2B4F1B818ABBAD7335DEFEA634726CF1D1AA4E0BA57 0DD9668C78E5ABC3FF30F1441ACB6BF7751B4C2D419E64B9BE6C5168A59C342A 1EE13C21FE50617EBA1B75B89F5C6BD7C1A49BC9E4B02F7DAA8B124B6C416B7B 900A01E389A07790E7B0FE749BB57262E9D927F0D8553BDFDA0A31847F3B8C39 8EAD95E9C8759D075A2B446987CEC47499043AC7E0C9498189E9BCC903751057 14C7678D722B415FDD9B291D1793785CC50BF27C7549CDF1EBDD346BB080C5AA 3BE2FFEAAA7AD5DCCD7EC5CB781061C51A2957E3F39FFF635145865DB89E3F11 E1C9DB2E195914EF342A54585259FFCCC575931DA88DC3BAF8E63712BB39C490 5255AB6C060D09C2A406FF9BF351D87964EC6788464246967473E8F72A284EF4 88F069CA800C964AC3E58B1E1F2E77F1D6C6EBB7C77AB7E652869438CCDF2414 3FD2A738D451604CB5AE028A3BC0A68FE1C9CBA009EB242AAF39C8FD1A081B68 E87568D8940305598BC9B9C7D98D8115805AFB57D0D91CAFBD485E4FE783EB36 EC6B9211F6E8A7D0CAD93830928BF04B85ED6B1459A754F039BA7BA9D5A3BE89 F145CF7EDC59FA9EE894AF8718383F12ECD58CF9970EE8D3E4728B3047535A10 ECA221DDB27F08CCCEDDA88A532E11A13876D244E62F68077325EAC41B774634 2F8765C8EB961BC889BA02433103D8066426C074220E9D0A5EEF57520414D474 CD90DE2DCC03346374ADF4AEEB3139EF5D69E9B1A77020D606C83174D05D841A 500AFDF0223A553D10D674FE2D259EA64E782ED854D9B04BE817915BCBC6C034 541A295B72008A1B2B6AE0663A489ECDFF4B2C8A599927835F3DC3B2A966F255 0EC53C26824ED9C7632D20945AE02E22566096F2BBDE5AEF3544931087670647 B16493DCFB295ACFB4C4DF184C26605C1CF540BA6DB97EA35C51D52DA5B9693A 4DA69958851B169E712A476B322B2CF9CA55ADACA34E17124CB5FF3AEC132369 1EC081FD513E265C40E9E156AA66C46AE74E75BE3801729644EAD8D84F9E4960 AB9313DF9E5FEF83A6FC5B1B0CBEEACA76909721653DD59AD6774D84D8449448 38489AD25EBA653A46465599A4E46177EDE5F44102DA66AFE41376A7BB816143 A3B4977AF108B9C00D023AEC9EE2BD29790B81E82E98FDF1016310B4F9B351B1 21A80F0C2F814C8955DFF09F0A905EC8C5892B870040BDDCEF5E7CC71B6BC01B B25ECDFF9286B7CA9FEED2D2D14BE183CAAD0177A0CE9706D3A995B1653453EB 12831DEE02AB022E7E0A4F329AAB8676072A1255BAE771433209B39274203E76 F08A561FD3E140D8451F6463FC80B73A52ABD9E9FBD20A703A82900A838DA63D 8FDB0AA6783C87C96866F9CA17358780965B3758164607633AC3B68AC5F34003 39868CB73C5CBE7C3B6915EB46BA7D3D61AE838251597C5B69B3C262DF4993C2 D9A2D3C35E78D5D147D40339410E75A76DD591B7B8F602D9716FE212B03A5A70 BE2BE7B3A57652D2C91F717DAAA7B4AF694F02D4CA9D80C46D7C2BA6745CDA16 370E2211255408CEB18187EB14AAF4B39903EA46684BA714746E31B1BFC8E208 D162DAD9212136EDD559586769E34E7E06F37AAC476560A3A33FE0CFEB747D67 935ADF079166765989F338DE7FD1367E5B8B1B9E2001DEFDFD5C571EE6E901EC 8E8B40BB7367B95342217BC9EC8CB166BD5C952AA322FE065CECECF58571E1B7 BA53CE0CEDBD7B26599B7DD41AA22538314A28A25FF5A74D3104D3ECDB6103EF 06D42B3C26D3D17A3FD407466ECE272E625F90C88A8B85F3C91FAD6913D8F162 8F8472FFBDF62989F99C30E961D5F3C9BEE81354FABF1067A9A4BF4EFBFDFAE8 2F6F9367ED3A7AF63C7B58469DD675A67F473FB66AC4EC04588CF1D6C4577A9D AFB0840FDA3BB3B0B4CD44E7671A7E81EB2E36A81DA664A4E9A31D5D3B350FDF C6F4B24712B7CC659B484625D787185EFC652CB3756EFE59B7B1C53D9560317D 967D4AA66086A702D0E609BF43F68DD897BC038C5DA7FF4BAE530665F5A6AA7F 55ADE198EDF7E00BD183D8BC8E7F4DBE8E61CF7C23D278B86989AF1348EC299B 65700641E0C894B16BCD9F95421D2390B34EC698943BDAE71E090DD9F05DA246 2DECC3F09A2E208CD2D06A8E13748A25A1289A9C449E6C7B49E61AD689540080 45188D42A7841ECF1009CEB22E2CD5955ACAF7B3FFFD7092AF73DEC5DD9680E9 4717DF00D716CB100584BF32CDAF833BE7AE1F710F006580C7241856143F7DDD D321AF68DAE36120F59DC7CEE93261B9AC2E2EDDD0CAA4701D5484C989529B84 233F02586F82EA4C6DA9CE8AD59C1178259F714849A5C9DCE8E366F4CB9A42B3 37687CF9D115EA23F1EDE67E30456CCFC01EE9D7B10DEB98DD4B98E9EE3D0D48 632B30AE05EF84262205A99C95977B8AF0097B22109D764885EFC78EBBB3FE48 0A118B31460305F7329D4B4056C1BCC42E18DB95066F2C0D56597F0852B5BD87 4AE3C0B6EB62D95CCDCAAA072E4A7482210CCFB624A7C07A714C59DE3FECE715 E271CAC8598F69D20EB85CFAE6AD3E98E22B4729FDC1399BA0F5170E730152C9 C0138A43484A493E7188F9F497D21050DF0ECDE96120D2C4443D49FB13024323 FC176F26D80350AE11BEB8E4B3493E9B93F3FD9A5849C2A096315CDCB4037CB7 14CFAEB4163DBEED7752D85A3727FCB633710D8F0E2E0277BBD36043BAEA6FF4 061EED24B6DF72D8BDC0001D23DD44CF319E8F424C177270DC8DA6A4FB10AC51 7DA231941BAC49A2D8600D7AE89DA6A7D3026B3BAE99CE6FC6D7D7D752A5CE9E 10221703B80741991F12FA9B91BE53885524CBAF6F8DE732C5D3D6A0AF9BD55D 517B6C9C67C9352AE09C2930F02BD63A710CCEB9D6D2580A02888EC2F8EAE842 4E173F92CFB5F4C97F5C5CAAEFE7C15B7218D06585C5DDBC4383FAE3D7B184C6 C378B27EE7320777F9E607774714A1DAF785DEF7C9BA43CA71395AB044F4B1DB A2A6C9FBE7FCEB197A59CC1CBDDE76CBC604C8671E0BCEF3C1CE3863F1DD6EAA CE141B57CF90C0E16513CBC4D4631D96DF6DAA30971E6B04839DF063837AD711 21C0EA9FC5F8AF98CCC13E0FA7F047753B185058EF0967A0F2180F5FA30D767F 129DACC9F8A3530CEB38EC2F1A8E8E59DEF1A673C197A32995B953AE244E33FD 093615F6651D5E25B5B71F74FC1D4925E968AE3F1D827718FF5D93CB8C9C9377 5DBEADF2813979EE30E1A5C8B95B7001972A994C0DB86A857BEAF4091D54441D E8D6CA65C951D16741EFA3043B035A42458927951A899EC8F868F19E5AF17498 4947B80C2D020CEE6F42C4B5B775F87A3436767639AFD51B95FC7656962D3808 6F3DE202C775828595E98CD5C07934D342EAAE29FE347F0DFCDFB1166F48131D 39D1839B33A6988F832C587A052CB7F052FBD75419FD8343EB5EAE54A12F73D7 7876DABA0B1EC5B0BDC1B15ACBD01D732B5C45CF5D73B454D0EDD67F506843F0 21BE670822D65240A4D4A529B7A5D78EBA0BB671362B36FE58005B05D062A4DA E3F13A3E5727FE455C26E086C4E72D8348215A955BF7FF265D97C9479136A2FE 3C71EB6103DD91E9D201E610E50B91A0546E68F16A9F9CA83EB4741CDB7073EF 186B926D31366504ABF2BA320EDE73BA4503C3E47A51553A8A4DAFB7B09664B5 4E7F2E1317B5C84DEFD402095024103FBD7E618D9F0D74FB3F0A28711B2E1881 67BD263F247DC6B860646C2566164AF8B0670712D949469489BE524D0729D664 4C95072CAFC945DE0C1185602BC24FFD5044EB5F610EBC769AA817006F5EB9FB 1FBC319D0B3B727C5C0FA2058130587B91518B485C5EC0DA4F48E47A14FCFF9C 02D5968EA8122653745ED966C26F5F3D82AAD1619943F4642D12C42F48D66CD7 EE109080589AB8E58193A1170E4E718C134A9C630E002CE7DAECB9695DBA6941 17B4A6EA1961BAD8FB58BD02ECE3EEC10BDDA9DC112D7774BD15B141540A31C0 9EEB72D7E5FC9BC6DF42F9FA003A5EB0DD354805A9E395158F265356A66B3376 F2ED47F4066C2B6CC3A92F1788162142AC0FFE512A6961988AB80B0F16D4829A 1436733421AA5CF3A0B609031053C89AF4416D8C57F1B10BD40AFFF068457485 0032D78DBF6E46116A4A8E7005FAEB616F22A0314E5F527955720D5455A6817B B9D51CA8ECB0DCE1DB6848FE8D647738053283E9AC99F3005570DD924464EC0E F028EFA9853C066198F5ED9D865B9475AF21ECF12E1101CDDF614DDF4FFAFE67 2830CA202F221D6A816DA26A131050ED101224DCC7A368D2CBDF92999097FA68 763B76765C9885D11C6A1D44384E1FE72C3CEC4385B49E937DD94E3666CFF4E3 A2C285D85948AEE46CD490CD44DD63978C96B83C79A290694F3273904352D476 77A239E30E41C975FD592E2D0E5995BAE39907DD6262F1D771343DA4157E7BC0 4B549FF51CFC89D6CF8F60A111EFD1E04B5FAF83A9CCA32802CC6293EEA0E94A 572887D402379C67CD81C66A5CED61E8E67B45DA25F4908B9B499CC7897D5CC4 F37C6BB2EE861E42559D8E9F6A461629DDB404B32E11C0A0550BDBF19C37B307 117F0381875D5B2096B4E20F0A0180535E3EF5324F96AC9EDDC107A94AA6A83A 9B78C8357BF62663A42A90F38A1BBE062C512D0F6E0B6D7AD447ED7E88E67E69 43F4CA5DD46D4CB416450681094369FF0AA8395AD3D2CEB415C96E176CD90519 D62AE79B52A6733DA46A639E44CC11FF7AD781AB12892EA228407247B06DDCC1 8ADC12FC0B2F563760B8F3129E43B6261B3F102713E756B31F394B742B19496D E0EA642B8779B4313762A37BA8F4B42653EEDA446DB1442D1782F241B1C055E7 5E0FF4DAFA5AEF8AF0D28554E6734C7E38C56DFAE024C2EE195C5186F772E22E 98AB633FBE636604C89DFDAFB9464D77F51533A42F1E1B58D5510828A8D5A98B 26FF99C063CBCA7FA1CEE25493E2365E0CBEC13F7442641D30433E02B0A361A9 835F0E696AAE908A4ABBAFD2D68D802168151E616184366FDE301F3B6198F3CC A23E0CD70C1A67821E1494C2A58A1005D05222307D9F21309FF94A5596073E19 B677C23CAAE0B98C87585A8DDC0717C8C88BAA8CEE6DAAE2D95323E9E2AFBFE1 0C4B4CB060B444DD7D1F7185906E443F7BB6B3D2F6C9EAA7A86116FC6CC1420A B0CB3BA1730A4625535CE44938F5918E4F88B05FB521CD3EBE326C34AA364896 2D2780DEE0552E7F8A5A905043FA76AC07CDE0F03D665057B697A1199C06D3C5 B362B32A4D60D7DF84DBE32C83C5E93E2AB6DBD57476E6B9B13744D734C0343B E1FADEF0CC8ADD270CF39947B64CD98A797BF1E3635E9F1A7FA23A3C1F8BAF0C 746E7BB35B8B6504563BCF53AC2E0D51293320CD138A2165239F47E94FE882C5 B922305ADFB8BBBFC5DC951C751BADA222933A107A3F4391BED6CAD06BFBE132 638496A58BC522B27BA3CDF640CA4635C0FB63890639DE751B68B45A36E10E58 7C140EE633B1CBABBED87A6B8B293DB47D6A1196FC3ACD5DA68C65DBF91EE1AD C62640260BFC99AB1CF16577A4E95E21FC9D76E6A7CABC96AB8910CD58A33CC4 F13326553CA24A71D182388DF19635CAFE0B910D52A096A0C2D94CA0F4CF80B6 479056AAEBABED5D6DB5B88C1B014AD931A1E952E84824BE1AAB56390171645C 693425ACFE259C5D7516E81C010DFA722976C8A70821FBBA66C817CCA6DB6848 54E29000C825D23C68C5881639615EBA2A8EE251E2B4A6BB756A63192CA87C8C E954517B4C8D47DEF3B7C7D0E381162C4835EF5DB8B77BD5C6CE40D6B76D6E9A 0488C86F99DA6ACA658D92FFA83977E72F1CF5A57FA16A9505C4CCE460402264 2D03BB1553F9208B1663ECC7ADB063A943A6F26705708B71ADEF85E42708D905 2F7D72AFEA25D7BC2A2664F9B4A048E51A9A97F1EB5E6D5C4ABEE7C5AF52487C 89515E4B0E793331D60C355DF805DA6CD633809ADEE8BCE5DAFE269312FB04E0 83EEBDD48372A3B0EE93D734A86ADF3D131765FB07AF39A224EA895A83C07652 30FC49A7AAA91EB83C6A1F8393AB7E73A638C357E384A893046EEBA4A8E9158D A97EFC7946F0044E946F1CF19DD3C5CAA9941DED16E9576E25D12A09B7344A73 36F81F5DCFD0C8F18E95771C6C0CCDF8BD7826ADE9A4944376EA019944A9D148 9E49CAA861EF9B6E5B0EBE767F71F13522A1F2704A2928EB7EF4EE843B7B2BA2 D0C848D4441050C302B7ECA3C081ED0E5E8CA7E5A9D5851B035C2F83E7F91C6E A784C62E2F02239382C57BA5161AECB9D53E6DA823376404B76DFE8401CD87D4 C0445AFFFD4BD5B315F521F5C3CD74E2087A62643A4436F033F34CA3E1DE7AC1 C3845141F03FE1C3A2673C7FFC47588AB23B75230237AF837AB6365D9CF5B6E7 45E741A0629017D9C926479C9A64E9C85E30C6391D2A9123279743A47C419D79 C40308C93289923DD75FBC15F7B9C1F9850938DAB0BA4E6811C6813D436B8284 4767134243A624BD89006057F6882B46D928D794A764ADE82F560BB8188FE4FA D83EF88817D78B4E48E59A498F0E278FD8D458ACE2F06FEE67 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMBX12 %!PS-AdobeFont-1.1: CMBX12 1.0 %%CreationDate: 1991 Aug 20 16:34:54 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMBX12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Bold) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMBX12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 12 /fi put dup 47 /slash put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 121 /y put readonly def /FontBBox{-53 -251 1139 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 2BDBF16FBC7512FAA308A093FE5F0364CD5660F74BEE96790DE35AFA90CCF712 B1805DA88AE375A04D99598EADFC625BDC1F9C315B6CF28C9BD427F32C745C99 AEBE70DAAED49EA45AF94F081934AA47894A370D698ABABDA4215500B190AF26 7FCFB7DDA2BC68605A4EF61ECCA3D61C684B47FFB5887A3BEDE0B4D30E8EBABF 20980C23312618EB0EAF289B2924FF4A334B85D98FD68545FDADB47F991E7390 B10EE86A46A5AF8866C010225024D5E5862D49DEB5D8ECCB95D94283C50A363D 68A49071445610F03CE3600945118A6BC0B3AA4593104E727261C68C4A47F809 D77E4CF27B3681F6B6F3AC498E45361BF9E01FAF5527F5E3CC790D3084674B3E 26296F3E03321B5C555D2458578A89E72D3166A3C5D740B3ABB127CF420C316D F957873DA04CF0DB25A73574A4DE2E4F2D5D4E8E0B430654CF7F341A1BDB3E26 77C194764EAD58C585F49EF10843FE020F9FDFD9008D660DE50B9BD7A2A87299 BC319E66D781101BB956E30643A19B93C8967E1AE4719F300BFE5866F0D6DA5E C55E171A24D3B707EFA325D47F473764E99BC8B1108D815CF2ACADFA6C4663E8 30855D673CE98AB78F5F829F7FA226AB57F07B3E7D4E7CE30ED3B7EB0D3035C5 148DA8D9FA34483414FDA8E3DC9E6C479E3EEE9A11A0547FC9085FA4631AD19C E936E0598E3197207FA7BB6E55CFD5EF72AEC12D9A9675241C7B00AD58FAF645 1297991B5D01701E82228D0313FC7C66B263BC79ACDDF9AAC48A3CBF42B96E38 583E1D059953076D68148DC8B6C9527B3A74CE7DEF788A11531F44120BDF0F61 0B2F3ED94EEBCDE4ACD23834C242AA4314B9EF98E4BE72DB76EBDD0A028CEA9D B4C38C1F2D24B8FDE686832FE96204552C820E45B6BAF0C3308742AE286B1FF9 C280A36904A89475920F5416A381546A74964A6B222D3B5D3BB33122C5940AF1 8750353EDA4A72FDC512074C59E8A6878922E4BEF0F7E95869EA0202B7C2084A C860B4F335F4BBF86307B030F68B574E9849452D51AEBECC5029E5BEDC3D62E8 33DDDBFD0CE68DC48C0B9321B35606105340886D28E84805E482C4A6B2FBB3F0 1E1284EC5EE0FB0E8BCF06F1FF958F370B1DE487F376E94D14AD974148F2ACA0 EABDAD749373E11B91E9A9FD45B937C19A3A5F4E7092477D1C93D8E23529EAD2 2E348BA1C4868A1530A359FAFEBE609BB254E144B58940846D1B2D34829362B2 C6D5246B7581E924038A0239FF76CDA5111A4DBE97D758E83A47F721E41897D7 08511F621AFB01BA14CE069EF39711F2DE85E7C58569E03A72C14FE4A93E778A 72913C2E4A746A523389B35CD1E197A6F964BEC17CDBACC61AD9EFD8548E9F29 1F9869FB026E20D756816508C360BCDC6D17118F50CD3FA4CDB7B6CD4BD563B9 E5059D6ABAD709F7B78A42CB9EFCF8D25B01639D6965F5F53B06B7B3FFCE1D1E 34C8F992A99CFCECE02D057B0FDCAEDE0287BB98C741E9CC0CA71EF4D52CA5F6 96CDE18F1659E0B583DA8CDFFDA0AD6A987C9CEA9C975CC447EA68E3E6FE364E 58AEE5500A8181C11C7E1F9D7B5D3FC36B4D8E6BCA8260563B60E40E178D204A B158D32F284A72E9BD7F5A613D8409201725F5896AF4F777508A7CCB75F10852 5ED22BB88C1985725769DE0B1C3400488C8775316F03BC8D615F0D68DD3CFDBF D402AEA23CD04670BF45F56F58355A5F0383CBD1E9C455A1A18051EE17217CC1 41D1B271FA4446A6924E71AA5B58CE6FFD5484301A94D02718CC8F62D4DBCE45 46E48973F6AD7A2C2334C5163DA596674B6830C53915C4DE306E6A194581F8B7 DDCE47FCF873FB4F82D8A6812F14FCBE6D0AAF86B27C2B8B2F49A2FA6CC5BCD2 43EAC234E0963CED32D661C867BB4CD570F06F911F59DB74A6C9D72BA0A6BBE2 D1621B26B21CF87AC14E9A81C37E70A45F374D0A7AA4217D857B8BF8CDE8A175 3043499980995BE5778ABAA3AE9998C6A4B7FB0BE1D512F4DE8CA7B3CFD678D9 1DE6DA6EDEBF11E620611A5301859E74BBF10C13E00FB75AB4507CEBC2343D59 1130D18DF575979BBD53FB02861D0DAFD12E1FFEBAEC3B81951172EF991C71FD 415AB5BB2310FFC9FA4B9CB912AAC0DE74DAFF18BB122DE384D04ED2E0841D74 2B2705C48D1D85C822F95A1C5B30FE3C4E057C537055E8ABBA4B6FC3767B32FC 8D24F9375ECDD8BF5D5C1A2F865FE272F8B0DF3AB537F9EE531BAB5D0617768C 216B93437EACBDE734C5466C931AAB9146231C8C961A4860EF64568C39EA822B 04E360A4CA47AD22DD756999A2851E8F71C79EAF610BCD50EB42C8E8999C29E3 3F4BA08CF71FEA49A1FDFDC93FE632C01A945908DBD457C8353C383B00502B8A 507FB4B3C78093661C1740D2F43BDE36A65D2A657CF4D79B588C19FD9215818E B8497E81466F236AA869336834A0DFD1157E71E802CBB97C80437960E8860660 67379F04D276DEFE4C16F6004E58AD58EB533B4F88A0331077F0C8448DBF601F D5E61099E20DA667B169E8DB4E42A2D573C156916C02442EE6D3ED76A5EFAF07 11528257F0FD5C4410C1B93EC2B11A7A169455C298ADD6E3AF7BE1F4257BEC5E 11D18F3F36AA148EED0A15F3A020CCE802F54C81676AF992D776804904BA8CB2 BE276CA063ABD07C127ED3A87A81C5BFAE13C168AF9400474791781D8174E9F5 2476A3D6889BCEADB4E649F678738C8C1108745D654D498A2FC299012AF23E84 7AD8B8641BF47E28553B806FAE136D88E82ECFAF581500732695D05D94B1BABA 8CE7A55F687B09588E278C477851F8C70E840BD6D4B2760052119278F6CD2930 17AD2F82C25E0603C146A463275F68CFB368FAF03DE91730B33AC3AA819A416C 364455644B89B247C2636641263D164329F208E91D0701382AB408CC8AB78869 7982332D3BD23783027D6BA7303F2B6E94AF439D96C6DE55E125B23797AA22FC 15B479690E726F15F590309D91672A7B4F27E6095B6E040E1BE5FCA226E0E6DF 12245891D4D0C2344D143112A59A9B77A85FBA683C729B422D0E13FFEA6A3888 C2C6775779BF62990F40C925083579D3A42B7CC7BF41DF6AA61DB64A81EE667E 7C72E03128C00EC1C4693A284FB9B16A6088F4127F1AF54A6BF3F3C294692FDA F5EE9DE90F730BBD3B0C924745A6A3ACFE3470CDAE7A0FAEAECEEDD71635E9D7 57927F76F682EF152D0CF0BA96D3A6E513BE6E15F38DDE838CE33CF9048594B4 98769A3CEE8EB6F083CAB3F0BE180C52EB6067518264D013908D666244A29C19 88939D13E37A601A05633F9877FC1942EED79C48213B0E51C9B7553FB3993951 6537062C21FE4296AC87F8C758A7F32E6AC5FDA42E68632B14731349D0BA1D37 634DBE0FD48E90C30435DFD055ADF391396D3FBC6F612B532CC8F01935457DAF 680A5F32633F402CCE46D21AF9719D29100C0FB36901597D93EA4AD60016246C B3A8C6B4F7E6D36130DFC9DAC39E78CBB19CE9D3FF532F5C587EB8F5C080A524 BA675AE439709FDBD0DE80983AACC0E34C9139736D4E0310DF48B14594C25175 737D9857A09ABD3FA25B37BC23B6F292283E52C1496D92CCFE0496CC312E331D 0D278E2CFFF8ED574CC804456AFFA9232884B27600C0B2EC4C2BD1073B25AB39 B4AED41BE5C587BE759998800FEF63736CBA3FB16E5F2436496ED773D3523789 7CCEAE2BB2B01761995B7C66FCFE46994D749238D63D716ADFAF7796A903EB73 3032B711EE3CA12497F0AC39C37EBE3757B1389DB79513FC8FD57359A69F4D99 CB8C98A979E10216C0EC9B395681F2E366B185BFB7FE9D81D678FD7D4373B45E 19ACE6260E0BBBA68CBD74DAB23E222AC4330368E7FC1F008F52015FA05EB280 1EFF7D27ED46CA937EF1D0A746128F9AAC5D2586124A625376E0684B77EA88FA 9F553160ACF30A5B82E85A8F9ED1AF3066B2EA0BC3F1577CF3DC2E76065F9AFC 1AF7D0A7D4BAE063313FF1AF58202505F3C8395ADFD71463242484A1CB39165A 95BDE6936753F373B6497D34D51359488C3D59964859E17A5D5FD29B5C719098 F7BB23547E5067910C4C65CC689C2A49D0BB62D4D352F9165235ED3F183314EF 1D1809B6A20702D49ABCC165ACEB6B4F864A9B316B85C714BFB1D2780DBA3D5C 58F5559F00BEE018EABAA02B4D8FFEB7ECA2C8348AA7C931A32160E70A087802 CD2C3C85B0D0700750FCCA3FACC9072113925DAED7F2C3571B72BF3071D0B851 43E366E22B316E3BAEA9651012E2E90A2184B7E44FE7BFA512427E5CB61CF018 AF3B73E54D84CEB1A209D3926C8469291A666142E4B22DD2BB77D4C9E4535AA9 61B0A25373C5BA616086BF66B200D05D428F05DE7138D780F4981F204C1FD4E4 3A8A2D1188CE583F99DACAD6E8546909464D11856AFFD7E384982F34FE41BE8F D3FD178BA6EC0741470CD93FA97AE8A93C791CD5D189F5DC6A79D7FF61D35509 B45853D824DFF1469E593B228DE442E9E6391D8503E2FFCA7921EAB4410E013B CF0E32EB70B96C607DCEFDE222A73CFE9042C1E54E18712EC0D9CB558A843393 4AC19231A2F2A3BDE4BB26A10FD9C929B6C5470BF625EC65B44A06FD02A49902 D0005546C024FBCF0D68FECEC7A553574FD5516A37EA2E5D5CF613032479EBA3 01EA0E53608C42F7FF79336BC8395551F1851C1AC80FA05D83E8A29F94677667 202B7EE0EAFA734DC16EBC30EB8E929F18C52468A37F8D5872381EA17B4EDE95 7ACD09520D66C0048569B75E7D7F8ADF08DDA4658CCC8088B0DBBA83AFDD325A 6BE1E987BB9B50F43131F3C6A246CF29A800CDC5A0D0893544BAD37412410D33 487F50EBF86B4DEFC78BE57BAA1BC03056FB82B94936DAC63B39AAA0FE4B6A91 A8D058EBFFEC8530D5BDF64A651E6A06E1E808B7FBB9922DD57FE110F6959A70 9AC412C0191C3085FF0FD671A2FF5DFFF688DEABF1052E2BB870C1EC3C884695 D3F6E92FE7817A34975AB23FD451069307764D002059699B23FD84D41A73D74B 8EC122E33769333412A0A78283278231D03D60C66EA149F02716EDE54A223E33 60F42A414ABDA0E8BD17EBAC34A322199846D38654E3CAFF13609B2034AB06F3 386CB8F363BB30C8833B6451B5A4B57F85FF25F20B09867B9E0A6E38D7407129 B7043AA912DA9293887C4115329C6F78D26D469D5FCF4E024B312AFB2212EB92 CC1B4FDC699811032C8132C31D332BCA9E521AFDDCD892F4D715AE509ADD47DD 83FA512DAC18F5B1A1570BC24996E138726DD9A5C4CBE6EE4E03FA292CBE5ACF B8FCA4614F334B9F7CDCD74A7AE5904AD3BDF0EEDCDD2E847EA51C232267E394 7C7487B324A143518C320D1F33CFB4D46AED8A68554D0A809EE5EB07CE7A9553 1CD85DB5D07ACC0A27C65176247774FA33C41D964866CF8582AEC4949749B1B6 E62BB6B1A0054F7E5FC8E9B466E1454188E60283F2D21A0237E18E97AD248330 C45A4EDAB16A06CD493594CE68650D5D3E5C4748DA4E0491407D798687FB3902 D3164E172E5F3EC9B4B81D4704E26466B1CEB09B4D3141C492639C329978597D D109FBB672746A60CBBF28D6E668A944546E4DC978BA9D84C9EBF01EEBA9C3BD 767E6FD3FB1132108677226C651F10E98920F966860A85272ED995875DE10EE6 BF081BCEE41C3361B9879DB89D633BEADB3CA961605C935B4B5673A793F87B4A 6141873240F8EE1874E0398D6A7DB73EFBD0FAE7F8CEC93DAB6AF1FD9D064C3B 2DFC9FEE9229EB1B5CF4596682A6EEB81DBE29D80FEF001C0ECE6448A061839C F0D91136D47F6E3184CA455CA69A2D28D40E838B9D6207533387A90CAB7BDE55 5624DDC0AC01DB38CCEFBC1548F6B3B1563D85B5E5D273C643AB7AFDC2E1D3C6 B8CDA0FE4E421D147F44C09C84AF807FB6C19C299079BD6A8F2E7C6A8043A323 2F230A4C18E4CD3EC89A183850CE389F6C5F7C35E3AC8548B4694C2D022010DD 25AC3DA210F9E467899B37699F7DF6BD68EB02A7E2885DAF877300C483210C68 AAFC439C458491A12730DE03F0B908A5569B1DB9BBAEB016883EB09028F3EB70 7F9857BB1E2E3AA1E2902F47D56F809F74F654D6F18907DFB9C647F39874B0DA 50D2E2F344C9DF81520871E899587AE0645142067DBCC155A327AD9CB8E66A6B B1CBE77983E3089BDC66E9C3FA8A7A003C06385068755B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMSY9 %!PS-AdobeFont-1.1: CMSY9 1.0 %%CreationDate: 1991 Aug 15 07:22:27 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMSY9) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.035 def /isFixedPitch false def end readonly def /FontName /CMSY9 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 13 /circlecopyrt put readonly def /FontBBox{-30 -958 1146 777}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052F09F9C8ADE9D907C058B87E9B6964 7D53359E51216774A4EAA1E2B58EC3176BD1184A633B951372B4198D4E8C5EF4 A213ACB58AA0A658908035BF2ED8531779838A960DFE2B27EA49C37156989C85 E21B3ABF72E39A89232CD9F4237FC80C9E64E8425AA3BEF7DED60B122A52922A 221A37D9A807DD01161779DDE7D31FF2B87F97C73D63EECDDA4C49501773468A 27D1663E0B62F461F6E40A5D6676D0037D33F24E2FAC2B0009AD3C8350CDF8CC 65BCA87979C36D14CB552E9A985E48BE4E88ECA16DF418749AF04FDD2B0E1380 D281BB2476BB45FF30946B247DFD7F57305FA87E50CA338121C71CDFDF927A9C 77FF14CB4A1D6D80356FB1171ED38C37702350497B44E42CE31DB2F493807DAA 15B887C671199A54C4C1294BC520F5538C15556BC43C9F62342B121C6DCD6C5F 491DA47FF360201EE21C08A781ED0589A6DF91B99FE118B9B29E4F068672E52F 1A06C514D91C4C937D4E642503392B1CD1BE8C2F499A1AD3753691F4D1DAB520 BDD769BAB70656DCE98FE5F77BE3D8633BECC0F8296D447419F73D58A556A872 53D139658EF30FE8E30E472DF06CA631B6F08402039CADB5B46166CEC30C10D0 0910E22AAA5632CB8F7FCB77BCD3BF38A5DABE2AC0CCABA535B03F338EFAA3E1 46480A4F905AE2C3E9000CB2F8519BFB4E0957F06C42602C10C0AF760AD41857 22664E61710936247988451E405A231578D43D8582F0904DAC9CD895E1404B6E E70669B1718F693EB4C8C9C610102905DD794D1AD2033F5CC015C5BA25AFC225 F70E4D61A8006C96CD099554110EBFFD0EE307BE01E75B825E46ADBB3C4702FE A3BCC8E48B8DAD4119C5D70579ACB5CA6693F17FA2F46195042088A93515D600 7EF1023FDE89E22515 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMR9 %!PS-AdobeFont-1.1: CMR9 1.0 %%CreationDate: 1991 Aug 20 16:39:59 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR9) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMR9 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 11 /ff put dup 12 /fi put dup 40 /parenleft put dup 41 /parenright put dup 44 /comma put dup 45 /hyphen put dup 47 /slash put dup 48 /zero put dup 50 /two put dup 56 /eight put dup 58 /colon put dup 67 /C put dup 69 /E put dup 87 /W put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 123 /endash put dup 127 /dieresis put readonly def /FontBBox{-39 -250 1036 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4 87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0 92A36FADB679CF58BAFDD3E51DFDD314B91A605515D729EE20C42505FD4E0835 3C9D365B14C003BC6DD352F0228A8C161F172D2551CD1C67CD0B1B21DED53203 046FAFF9B1129167921DD82C5964F9DDDFE0D2686875BD075FC81831A941F20E C5CD90040A092E559F6D1D3B0E9BB71733595AE0EA6093F986377A96060BF12A A1B525CD9FA741FE051DD54A32BECD55A868DD63119A4370F8322CCBEC889BC2 A723CB4015FC4AA90AE873EA14DE13382CA9CF0D8DFB65F0ABEDFD9A64BB3F4D 731E2E1C9A1789228FF44116230A70C339C9819676022AB31B5C9C589AE9094B 09882051AD4637C1710D93E8DD117B4E7B478493B91EA6306FDB3FA6D738AAB1 49FBB21A00AC2A999C21445DE3177F21D8B6AAB33869C882613EA6B5EC56476B 5634181ECBF03BFEDB57F079EACE3B334F6F384BDF9D70AEBD592C8ECF21378B 54A8B5DBF7CB9282E16AA517E14843909339B5E7C55B038BF3BB493F3B884A1C C25F9E8FB912CBE23199AD9D2C3E573727701BA301526C66C3617B9514D6F11F 11930B1D97C17816C85B1BFD9B973A191B33CC3B391815AD14F1CBE935942AEC D4004E6BEF379066FD72209DC88D2E634E79BCC2B98C766CBD92C561F2703F8A 109E6C6CEC7B866F2FC7ADF646BF492E520319F3B949AB5D84AE990B33344A40 3971F58DFDF8D8D67FA0B8F2A0D884F8C09A5A721319B911DBA0A35903877343 C37BC36C5EB32353272D1E6ED5FCA611BE319A7E1E842CB7576E7A6CEE8D4AEE 7F38E289CF2DC680A4B09B95A6C2B29FC7F6DCD978F3034A513B70B1C7FF0FDE D60CADF19E16CABA7366092920840F5CE6308991F0F44CA809AA700C201EC390 ED4EAC60BDE6055F57FF4C7B8986517AE0C3A8DB1DB536B9A28FBC4D8C7F9AB0 D0BF716E57B8E85E89BA2467F70ED63B543CC2B704ABEACD342DD95E6BCCF77F 396A57438B91B96705E865C7CF7EDD64DC35EC7CDDCD32776E1D948699EB3099 DA1CAD6C6F310CE3CA680C8832A122D89EE154D0C52BFE588BB866396F5E3FA8 D97F7201EF1C6A02204B4742D8953D8E0BE5668F411972D95E5440201B80E096 09AC93AF81C1F4CE8CDAF9F6C24FE3C6E5EF09F998D851C6EC389938AC3FD3BF 1E997A12877C303971DC12762B850749ADEC4B7D019D7FA31831611A882367F6 8F5B6708606579D43D0944B07B0B67C98A82EC3C6B8E84EB2723F8C0CA85E1CA EFBEBAAD339B938393F30A7CB5B1B948956E012ECAE29EEB5F1A7517541728D1 A26E9A526B540439E38757B6792596B8CAAFD0E6657CA44B4C013AD00D564DDF 7D387F239F72DC29C8FB68448A6B9731FDC0AE16A2CC5EC7A6B2617D47C12F3E 0C1412D461F5E4E6CA4FC08EE91DE814778E52DEA0EBC584E74F0FA6A7EA069D 68836E22755012AE90E1E84DC45C6EFB363A36C787E4D0662AF85465C2AC1763 E7ECC12764D8216A1411EF4EEDE79639F3BC6DC35DC538312A4663C3422534FC 03F2C3B1E83610AAF6AEE5F32C5B94445E8A3F3215E3B788B36D49DE55C0A2BC 0674896A044854DD9A76DBE7AE3CDBA136687B3F0D5C276544EE640EB07EF485 545C16E65089B514D81CF1532F684F51C2D63CAE911D29B51EB35F9F9002B371 8CA995C71A499054FF113037020784F9168378F99697F33A8ACDD9B38F5C8894 E718410B87EF89A5BE658D64890EFEA5CA2E115478240EFCA056811021CD2BE7 E9D1C93A04DB94D223E51D1464E1F9D30678F90AC212A71B8587529257784621 34D10C2604B1E1961A75FA161F3BD3BACFF9965FC85964BA38A64E14D7EC7189 F077EF22D317E9CDAB2AEB2FE8779A6D0F6ABAF82139C66E12F1D4A8F1E70075 2799BF42E40C9FF01E37A7B0C0A1B531E260E8B9EC433E6D4A525C54894CF70F 99F47A01407557904390A745F63A4B08EAE652CB5AEE62B2FF8A7BBF2D752B11 19C89318331195A3919A6F0D220788D54C721E950DD0E445A071F94ED7EC626F 5B9A0210ABCFA48E33F667A89F91097F6569800ACB43B2169B5BBFA09800DAF3 11127FDFCF2320BADC0D042A8576431010DE2E120BB03E88DAF86A96839A0E18 D2742851CD3205A898BA6F5A7DFA274454D3E56BF27E7BA6D95DCF76186A7CD1 BD855960DC4B519B2D0F76D6D64DB6580AD2166D3ED3234CF06C7D3685B9CF77 85E9857916AC9C9AAD24A04390029F68B8503DDC04C4DB121A19B48769990268 E1BE0F441683FBF6F4658F1415C142F34270182725428A9EAB97ED1856B59BEC 3E2F512F5D8E5BEB2BD5FBA1B8E575511C909C0948B3B3C65E16798AD5DBB647 C50379AB793A91852B246A200B7BE450BE5368C7B24908EFB33ECC7B054CC435 B1CFF025549A44B4CEFEBCE9E81093BE8B7481B370D36EA0AF8C180FBEBADCBA CAA45D1229905880A8FC6F4FD4AAD1B049EACEF00D8059860264CBC73940CB4D 14BFD7291AA01BE89420C0E32364280CED4AC70C55F58994BE54A5F474F1911E 4330405306A96E72999943A8B1EAA5767C13F3A53861C3DA12498824173E4BF6 CAD50F16357EDF0D654DAA3C271CC9B959F99A699D27EA8E8DBE5499554A25DD B1444A383C8A2AA4CB90344A8A5E730B7F76D3DB044C6E51F384722968FFAD1B CCF926D7C98CE361217909F694DE905E542B960FCCA0CCFBA8EC56EF3B6BC365 B9B332F1D06D2FC7B0A4F2EA26E471288DB8276BE6EA0BE60EA31E8B2DE3F1BB 7A0FC190DCCF59FD4B8EB405B44D6C0E61B3208AE51F20845E7B1B4209557151 33C29AEC4560366163C1825A10B9B8CD8D7F18B854142F799C668D2AF3EF472D 0883767C94F06D01F5ADE9747905F98AB82AB97B77011286E49E391E76F8F425 A6658218B8DDA976CA686D7267D32A65BFEEAD5218439E0F4456903A474CB844 60625C64703F2AB0A04E94E27169DCB566B48E6091D81E38E757A26B54AC88D7 BE5395DECB1D10055B26D163EF483DB243A4CC0F3FB8BC44A25CA55241CE4254 DE4F0928532E4F49792ED86BFB5DF4EB0124E35F645BFB2835A5A86DD7E1071F 98424BFD86E9592044993C7F5CD80BDD2862D90D3C170E6E906F5DACF6E359BE DFC1B0375504EB37A796BBC83DF28B60A36E23DC67C33F909D364BAB8C29B7D5 34744A657C17457BBC728DF4495AFDC61FFE2A4D96EFE687145941E7C3C76692 808E796CB6BA4A64450218ADEF3E41916F9C3FC721E6F9040250FCD20724F2AC C033E8D59C51E8D0541B4393E27E6914E81C0812A618B7233091583B2900D949 9BD0876601635129AB360F54A75C7C157B9C7C508D5EAFF7F764BD591DBB8F80 1D4307CA0961B6E7042F06572D5E89455CC8469C6AFEC9466DDE99FD31F631B7 5CB7F3A695551C1AA3B59CAF02DB0DDC59FD592077EC65BD38E657F85F94ECB0 57411DEAE5833B235AC52E3F0F5BF98473A7B528AC6298899E2E48A622939620 5D59B925CDAA42A154CB93C50F07F9F903B11B98E8175B9A2BA1AA84DC99726D 76E83E4ADFEAB2DF32203749F7CF9465E61D9DE70E6F4920E68C2CCBA9B57CE8 58AAECC663FD086669E1E0E579D11FADE022CC09FC5F509BAD80641C50F5A766 DA2B439F450E90009B82F64FCF3BAD28CF43CF153A3BB5F0FA15F5DAF7854D6C 5A357AB7E1BEC9796B06F6D0ACC2D71D6B8A7796F8A3F38B270C8DC031841E94 F07357156E62FBB9CCD0C4E39E8956F4CBC999E6506D848A82338DA8F83F8CD7 0EDE3A4F0D20565B8782F82DF53B45D82B0A4A6CDDB9B0F7E33E9099FAA1FE9D F0A9C0604FD1090EAAEF240575E19B52E8197DAF9AECB5B3043F31A5CD3C6552 F4B7E75ED197A3C88DBE86CB7F09FF471A6951279167D4676F647C6E9F9DA91F BA94B169F645C8408E3A58C2A89B4776E75010A0C689A1C105E3E7C426CC55B5 9C8FAD7AA4F171F2F36E921F6D64B168654AAE793579E96085F1BEB249CB4C8B CC7E1D9FD7FA009DC773B82BF524C91144AF6B81B0E00247D6391AB414E3F2A1 5B1E1674B6D42210779AF7D0EBA094E14531DEBBFBC4A9B40B8F6911617838EA 0F83F2C54FDA18A6FDCFF659BA8620F3781966449AD41377B95F81C9F79723FD F42FD319B6D01473A4198AB9550013D530916E2DE2C3A4FFB1EAC3D0B5EF29EF 5FB495EA64E4B38FDC3F9B0654BBE15B6E7CCFF1CF269A5D48B8AE5C820239C2 0D82D2F58063A6D43CB74C2C6062AEF47C54415679EE90DAAD091BFC200DA62B 546E43D3E88D86E312606E99F3E113CD2669847D0F2212A4F13AED6C959F55E4 E6A8F4AC38889D0001F4B3D26E6EEA2F09AE31F33BA36B9960EF653F7698BEF3 B49B5DCB59955CD50B2EFCC9E1D28C29261A4AC5989E1BE4897A51431C62E775 262F34DAF5C5E21BCC6BF38AC256A12EB84664E3F312AEB6FBD3290B9ECD04DE BE59F988D364DB84BF8B1996E08195B0FFEF060809A5ABC8C360C3AB4D73AF4A 9E13685E241C1B01A5E6D8C3A0BB449FB514C7439F6BACF596A017122A849B90 9B1363FDA9FA5160D2D43FB1F84EDEEC3A0BCC74CF8041430DE96C8FD50C47F1 8A06B42905927959E56FAAF3A3B8069442EBCB2D06E982C697CEE100CE9C6A64 33FDBC260F2F4103D3E8EF80286C5DA1A274D6D68E7B6AF701DCBF0CD7EEB585 A76059139EB26F53891166D62EEFE47FC32920F5EC6B008EC22691212C3A800E 8CB4726CE5E0684CFAD723FAB23A8328EBFFBC99A8ABA8DC4F4EB19CF6F29C16 5B6581BFE0B768D1697EFC5C4F607C7DB7391DEAB816E8B162D36B021E57B9D4 5F5640C9FC088E53BFA940403AD58512A3E512799DE5589FE0C3DBFC1C80EC90 DCB181CCE3A1E55BBC2B00157C4515267F2663AC6626B6715A4801241CDB073B 7F77ADA40859967F4AA232066BF71C40AC79E417CD595029F604DBDBCA3DB373 D6F772AE14F8F4BCA45D29627A5E56B8441D1639B4C87579C5B168CAF4C658BA 6D024EE26E0C092D846F89F0E94D9FAF04BAF018B51B94564A63CE541F3E4DBD 2A0D5017454C53495EAB14CF1AED999F2CA673481F41B6B1275075EDE34EB1D3 023696682FA454FF35E570E18CF26A9B8A22F6EF110BAA1466D6AE9A1F524921 BF1D8566654EC7DF3AAB9B4EAF283D6B33C75CAE7036D4EED8E257776A6EE885 692B2A2D71972050500DCD14A883A0CF3A1025E53E072FBCC180158034FD4AD8 7BF35F8327C3D210037A8F914DA581A73DEFF345D7C175285E790D9208FFE061 B081D1AD6CED6DE50867B0AC373ABDF3FA51CF9682F6015CD889C4B0C69B70FE FDCF9D935BBC427ABA9E26EFA7EF1B86B0EEB6B502F0EEC4E0DC98341086A3D0 4EEE45A13B9F803467AF3D4AFA5BF5A54D168A2F653740450AF6CF69697578A7 7B5E92A8B00BFE4BF58E5294D5D50B0D8540C08BB94030A55A96E539DEEDDF39 FED65C6CB982BCE1D8981FF008F4C5647963CDB90929661FC8BFBC582F8037BD 99592562DAC0DDD2D72860F93118374C2E3910C667FC4E328D940A4A7A672CB1 93CAE32AF31DC87E228C1828EB2736EE12925E2D2E66BA93A8226DD8179341BE 73C2FB9B983D00582F43B207B0C81FC3EBD642FECDFF15CA3B49641333681C3E 02F51D54344F93DA0024EA2212753414784E87C7CCDB937E6207E465F1B988D4 61A385C6BC7232341A3F0EE1FF10062F772A7B47CF7775FB7391708FE36EBDA5 ABC89FEF0BF3DA640CD12C9969595B716E54A6826CE78235851AF28C9F74E114 ACAFBF692D9E73BC22BA330DD71A9B692D451740DFA9A7205AC66FBEF3862F09 08BD3D72231808CB090485A572A07F0877646F46EBE0AF9CC4D8704CB1383F49 4839920B0EB14583FBD3BA22D5E4B9DF1D706872619A570004BCFAC96E244209 A0551A50303B279ED60040D7F57EC77A090DA56783DCF70208F610A54C1C533F 739FE916610450F53DBE4E36E0BE47541370242FBBCA11085D80A389D4CFCF3D F28D7127DF59F9DAA3AF4AE2DE775FC6236D856E85C84053B06B68AAF84448ED FF6F78CFF74364FC6062BE60AC33512B624E22E6FD750A9065F23E6049C8FBE6 77AF540B5563D6A337B3D1B4520F9543B764AB58E984E95F41E404CCFD37C439 6F93420C6148F82D94606CF13CB7504973089A95EAB14FBBE0E71071B6DCCFDF FC3E8583B54F7E380E213817E48F698384B52384E8C73E5C2DBEAC3E6D1FBB54 40727500ABA807D8FEBF025022211BA0B1258DACA891DFFE696EA912AB151818 F5DDF08598FF509E84C2EF472902F51A3965A1B9DF8B139DAF8E3E105983FAA5 672A9ED5D32EDCAC4309A91E3F67108287F715D5C5A485A7B02B1AC45E855F51 A4AAB95E8CC643C24061404EEE1FF684459B45D148D5B59E8AD1AA1948F3ED35 FA37DD213339F50599CAF405D37FFEF35785F1FA8905A87B2498FD5167DAC2BF 8CD30F0301DCA42BF2F68875F85710A3F2A6A744B5E992822BB62ABAA4303C29 C3C593AF17888943476EB37F3EE44298BFC443100B0865A7FD538DE78BD75488 F9A3C19CEA0E56CFE71C3AB4218B715EA3DE6F305B52A354773476C6C3FC1BBC 10F9E30F3C77DFA2E66150CB991E28C8509D54F1F95FA765B9D8858823524484 966BA830B50C83A65C79DA506CB40BB5BB815993506660DFF7CC4D557CBCC31A 5A36AB6AE6B1618B1BD4D4B8CF3DEF3EF5085284A4F389D955FC7F0D84120129 2CE9920311C3FF8AA47EA4287337203DC9F422AE24A74AA1E8EB1E19C1B0DD5F C8EB1746660936B9CD47E123E9D8DD1F23CBD178CBCC12CBB96E2A5348399316 BC06DDEBD2BA4234DC7824438E14357A481FF915E9346C9EC9673EF57765B326 2AB5FBC54FB713E92DBAD79EBED6DB3F86FF90FF4C32B5710371D9009DD63C6D 1C6CFFC26757A8F4F3549A0A4A77EEA270BDC07487F4B2A2F30F796AE155A745 A59972E235A70F9B5F71EE30035C4D75DBB3F4B24E71FBB12AC4652C019C34D2 B63CB4AC246C2D85BAAE011BFCE815FEDA2333BDF35519D84EC6E76940BE18F0 CE105599C2A9F02CC1CFD3AF0CCD8F391F570090B6D4480F92D6485E0380AF3C 50934C12014594627B5ED03D1FF4D21AC333435BFF877FF5FF1DB4D5530868A6 6D501F2F01CB03ABD5F32F2D4EF62FF63B5DA343278D9625D06719157EE25AAF 3128559AC52CA0ED81EB77301FED2B656FFDE78EC791842F2BF9116810F33036 CF9812FFA03B58ED26D31F783F8A0169ABC46B7AE8A13B19504F3AFB15A53FA8 A07DA60E86AB9260419BF7A46AFA1783D845431EF6090DB38D0CA451D887C96B C4F8000054890BB9008B10D4EA43C47E80AF5DFA1B431E4C54FE13E7AEF8DE28 2A6D61B0A7CCDABB14CFB653A276D519D395E12125D94C5D3F829C0FFF97DB2E A68223FDC299FC393C579CEE75826A3DB2A47EBCAAD09B6F5005B41E762FFB07 57CB1D85A7086FD0CE450D258175F659C90DCD85D6EA7F4CE3D27FDBD4B6919F E1FB5DB708282D3CA02370D0641C32D02CA32114F6249A7A0C35C5363AFC93C5 04677500F82F6F52E40055AEA681D33F3C1C885FC5EB69F21D2E1383C599C316 3095740E0A9FCF457786FF2D1F5A02898165427CB6873FB08ED95213E7244733 6B3016653EB3FD37E862693DC555F66B1E717A6CB641ADE9B379B1C6D56E67E7 1F4963FE9BE0C85A094415358685B7BE61A62975C5A2CEBA4829D55B992133C0 7B4ADA41501E1FB31E87F708D9BBDEB53C999CE16D444212BCAD8D199E35D2CA 2A71673D5B6887E1C479FAE2FA2ACBD68C95576B4EAC36FC35B44BB628C370A2 4295F5F090FC54DF0196C5156EF3A7F339A9201F63382A078B3A4E7B75BA54D4 027AAEC74B1412A75B73DF40B4B9D33F3D6CE22696CBB0FD2E4F052E209BE5D1 E383F1C3AB9F8C71743B606C0BF6A95DEE0A04E67025942401EC51D49FA5949D 94B4A48F27650957702FA9D8BB94885DD868192B598509AEEF1101F9D818E475 73DD189E3717424A2543EE32309F693D9B83F2BFB4CC4BC74ABDC3BA614C0B71 709824DD295D80C0747247C81125AAE0BD60993F5849F358B656768FAA4618C5 5DEDBCD4FA5B9B9AE1EF5ADE37BCD864A38EA42083EEA026A8A173882339F926 AB883293C23AC99EED83C7A899DB974F084A481B6D12C613544070B24CEE40EC B17613D51A86F05AB73A48209ECFAB8F16D66EC0F92F5E1150A3A00F489537D3 3D2DDD250F5E3F80E71124D5BE546F7545B44B8448AF31DBEECA992DD4C69987 A5AE16FB9A4C9B05D24E9F0A31D4090211AC1189BE14B17FBAF3E7D1A085D7A1 1C9219D9DC473AF3943546BE45107E1B7D20203759563976218950972C3EAE66 905327BEDC2ADADFC579C12667141F631C130291FCDF4C8CC798C15BD7CD1A9C CF031D51920AC5DF0DF3BB3DD61B9F0F625B583B3B6F0CB5CCC87D3F5582A836 2F49925ABA709418B2828B0F91FA07B685F79B55C0E027AABFAE4DC9C63858AE 1BE5614FE1949D0F143579BA22D8217A3282F3054362F02C9F795783274E3EF9 2A7FD99F05B876DCF98BC0A5537652A60590B28EAAF19E07BF8B3D3CDFDA0150 370E1F2E2AD87C9561CF5B61309510E69FAB26C3FCE40F57130DEB0E8D475FBD 3B971AAB5E6A9285CD4B3FB38C22C81332BA1282904CE0F5D386B63AC36DFBC2 635E64CFB2C4457D42D494B7C25AB3AF89BF07E3B32330AF6498438387AFE7DA 64C708766FDD8477888687A54679E0B03E6F6D179DD993A23542CF2B11F09F95 975766C1E07C70CF22E4DA21D6B91361AB22064F903FC1F77177EB379D334D90 92881BB7786EAB04136337BD7843546CDAA0EE38A854CFDE6E8A9D4A09E24263 3374E451E8149ABF020B7DFF1D4291E3524E775AA28590234E9CF63229CED33F 491D7F5FC15F522AB5AD71F404DEA9644AF00F808F92EE39761A9CF00583B93B 4A517E26548A50D199307B0B35522D808CF3E2D3A92AC5340B0A666DA56B4B22 C6AC5D285DEC777A0462584EF622D1FD26B0B7F5A53DB90E8F71DC13F23193B6 64CEC0C11964CE28CBBFA4684C0D0E759C85C51E3CEB1659A0AB1366721BDCC5 1C90366015A9693B837168199FEA7671B711AD4DD5C67DDB169D40126C3AFA4D D658638B505D9B01C92159ECD7CD46C8409ACE3D534CE817796F1F543B7E5F02 CF5E78995E5A7846E731B4FEADB79884F4407C910CE4629B0CB8F7D634B0FFFA 314DC7C2BFABD0CA873961A2A9F9134F6EAF652E78D8C6BC91B497824A365FE8 A38E06A4CC084C130BDF099813B7EF6A7F3318323FE2FC16112A7EA9B0D3A909 61ED952AFD4690542158CFE958C7DFA8C9FCBF44040FCCBC327101F925E4F5FC B40C76760968422ED38AD94D0DD54D19DDDC0A00921F25CFDEA1FF15896AF1F5 EF6E31E69D54B4DEB79CA98C01BC9C82AE7948E2E258965A051F0EDD51E04BE2 7AD4459AE1BF648CB30D0CDA0418F66B0F381E584D6E0C68DE233CD58D36CD76 3A674A0EDC7138A68735EC57AEAB4D76CEE0EE0E16A161E0C6997A109E95DDFD DCBC39B3E11F99275F7A8F7E17E23CE2EC2A1CF158A01A2108525628F2DDB9F4 BFD360D50DD703044023B429210A40DCD736B26D322B30422698DDE0BB26453A A88259088D606F48432AC312C59126577AE20195A9500906F08D3591803228E2 81566A441CB8F535515E078A58D427BACF44ABA178A198E285834D87DDA2216B 01D916A63BF3C50F920C1D9243D835A18CE04926D1DE1BD7BD0F621C02768512 805AEA43862983214BB394CD950A70083732FE31AD8FE4CBE17382E70FCA9F41 2A0903BC901FD68BFAD60333330E112ABF427C350406BB1163390FCA2DB97B20 AA129AD81475B3A75FA903B424B3800F0BA0F3BED0BB92A7484E980C7E75D0A2 0D419173BC6F621B1E40A496B66FFCF6D4FC1C481B730F739777F932E923087B 5CF5D486489524A3D2F0F15A95B359B238C85F5E8D5C110248362A90814508D2 296D8F11A63F59046560EBB660AD570F8A3A1B090338 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMR10 %!PS-AdobeFont-1.1: CMR10 1.00B %%CreationDate: 1992 Feb 19 19:54:52 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00B) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMR10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 40 /parenleft put dup 41 /parenright put dup 45 /hyphen put dup 46 /period put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 53 /five put dup 54 /six put dup 56 /eight put dup 66 /B put dup 68 /D put dup 69 /E put dup 102 /f put dup 111 /o put dup 114 /r put dup 124 /emdash put readonly def /FontBBox{-251 -250 1009 969}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4 87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0 92A36FAC8D27F9087AFEEA2096F839A2BC4B937F24E080EF7C0F9374A18D565C 295A05210DB96A23175AC59A9BD0147A310EF49C551A417E0A22703F94FF7B75 409A5D417DA6730A69E310FA6A4229FC7E4F620B0FC4C63C50E99E179EB51E4C 4BC45217722F1E8E40F1E1428E792EAFE05C5A50D38C52114DFCD24D54027CBF 2512DD116F0463DE4052A7AD53B641A27E81E481947884CE35661B49153FA19E 0A2A860C7B61558671303DE6AE06A80E4E450E17067676E6BBB42A9A24ACBC3E B0CA7B7A3BFEA84FED39CCFB6D545BB2BCC49E5E16976407AB9D94556CD4F008 24EF579B6800B6DC3AAF840B3FC6822872368E3B4274DD06CA36AF8F6346C11B 43C772CC242F3B212C4BD7018D71A1A74C9A94ED0093A5FB6557F4E0751047AF D72098ECA301B8AE68110F983796E581F106144951DF5B750432A230FDA3B575 5A38B5E7972AABC12306A01A99FCF8189D71B8DBF49550BAEA9CF1B97CBFC7CC 96498ECC938B1A1710B670657DE923A659DB8757147B140A48067328E7E3F9C3 7D1888B284904301450CE0BC15EEEA00E48CCD6388F3FC3BE18EFA2C389E5E30 A01122D4441EBDC07E8FF810DAC4B013B1B89F5E18548EFFA31C3777BB187362 FBBE6623184ECD991A057D130019D498D2ED4D2564124D648B1E0956E861DE83 22DE4B89AD33CEC6DD6BC2744D542521314697AC87F8582E18ACD9233CB483DE 3038D43DEE9C4101EC3001E16A8AB4DBF57849C544A743267A6C9B510BA2D4BA A94F5957E3FA951B817B69BEDF51BE484A6FA1B22079BB32D468F393A6187502 C4D904A26BA22D3EA5867045C5621797FB5B6216077AF948D21F19461C01EB6D 54A084D3DCC5ABC5DF3CADC870236751D9EF221AC1E7BD29FDC20E11094E2852 779FC5C0D5DB9D3C8E4443F64E4037AC19B46A1050451ECEB053DC8EB7B1FC8E 4B8175703FEC53549A80FA0B8B14AD07A99A7BEF99111BABBBEDB83B50CB2D6E 44036DA3DE4A6BB700EFA22290B3DC8113DB1B383EC98F8367ECA284490AE8E5 F3B97181DAD701B0E882A72BF7C8B1A634A3D258A989B280B4D3C402EFAEC87B 7806F8C1C163A406C10DEEF835FB8316A4935ED92E290D81BE763750E44E585F 4C8954334016AB3ED796DCAAD69802B9A233F3E3AD1FFBBD5621AFEC9409A993 19C3C5AB0000419F673E4C6AF2DC60682C86E59CDF6EB07B47DD67372B7DFBB1 C1FCE96A596D70BDBD81A4E43073CAE68CF09004DC142553CE10E655077008C7 08D115F60CE08897614E0E7E394668D9FDF44F024CEC0C1C46B244BB13B526C4 40631902B92C516F671CBD98E454F752CE74135975F3602396A1B7C3D1906E28 27AB2FD80B579D04C678DC7D453F813638EFA565CADF3958184CF236FA208498 2A94147D64CF6D24C7398FADD8342556EA418BA79389C14B53D8ACB9A8A317BA 18287D2415695DE264DAC055D267FD34D18C65CBAB090E92DC2D363DCBE217F0 AA2588D08652288FE7AC7559D8CEC5175D2D51D462DB7E2B61481F78C14D62FD B3B1963A9545E21B0BF87A7351F26E99CEC1CBCA4B0B8145DCE186115A250D2D 670BC208A6B182ABF207C39015F4605D10C2BF46D44EC8836B9FC33A70C50FBF AEF60BE0F793BED678FFE181B94938810CBB5B168B9B471A2EB79411CF355A9E F3F028A0BAFF629CFE81D098BAFD5B299B012DCADFEB8FE99007AC7E0C796555 994F56AE1C4CEE12254DD6EC68DEE62A7C503538F9EB6E740C67F95A61987000 720CC9DCA77D93EBC04B795CDD1546675AE16824DD84B6CA375598B6C439A2E9 0C52ED1801D2E1E0890E1A6EC8766C28863DA14FEBA136DF4682BEDCBAF769DD 3B13E4623E5483EE6DB09425F9F93C90B6BA8D659ADFB1FFC9ACBC7A181BDAC9 0B4DB7B15EA4364D953F5ED0291E769A232469205E204A324D4F6E944A54C759 12111B09018D997F71C97427C64D44FE0B82D17147B4210E3E7186BFB6B28FF1 F37B8FB91EDDED7CB0CCAC3BA113FD7F4D2684211B54D3C648893459F458D227 88CAA0F4EB18FC4AD11F7AF9BA6A882A92A1C972B81468233C975895C3666672 2B6902434B0C6F3E212E204501BE1F0280ADD00B0D710C59D36EF01BF1195E13 9B996499B4D9943C8C07763AF1728E513C78D33916C17CD28C7DFFB56F8189F1 BB726594E0AC03A3AA96E67273D8F8F767DD71B7CBEC3BB889A0E72F4990B574 3F5CAF09A815E69DBC8D07829924920D0166D5E70AACF63D6E76157E1AD9CF03 57E8E8784F89D70C92B0683858204E8E9D0B9EC2A6354ED93DB5D8385860E45D B0AE996DA1335970F0905663FC5B4143627CAE5176FED1174738451AAD0977A3 4978C608F1CD1162B9EB34373AD866E717DE6E47293FDB6D07FA1FDD6FFBD073 811AA5BF0E4076CD880C9E805174E3D557B492DB8CFFBDFD47035B035AE29C3A 06E45290547F9514D0985873413CC479F2BFEE2149B298747F32CF6F9CC42280 8BF7F6E086C36B19B0518363F7569FEDC49D2047CE034992D2A71A7979BBC46A F84B3AEBC24924F91E1E56EE123249EB8D917A625DF18DA3FB3746B18DF79874 68DBA817970B1C096E79A8D95A3FEEFA928AEEDEB616B6F030268A40BCFD34EF F9036697395846B96AC62E1287CC1F734DE4D0F1499C236B4108CA372C472368 AC9203B3B5DCEB390A02A157DC02808ED6399FDAD1F1A23242FDE2F970239102 65D01A4F17437231B8E6D10EF4F6DAF8B8C69CAD2EFFE153EABD2A55D8C79D5A 690F82DDD9772E6650AA5BBD82162A58B3D165893B130A6B2EE70E39597F18D4 8320BD92AF2977A31C428A0721F95BA300663D982F948467C4D7B9F2FA0AF73C 744075BF911B47D18CA303477EDEFC951B817B195B8F0054FCEA9E11B0714E51 81428392943AF910F505AFBE1D4F983AFD8FF3ACB932D6E12379C170B312BB06 7D73BA56C7508BACE9AE92C7183A204F5A312AEEB79D2CA7DDD469399C880B1E B9BDE4079313E9402F984B8FDD92871D5F58B694EEC5B26D2342A1C63E510917 ABB319027CEE1F45662A8331B2E3A8D6E740C6B9CCE5F66996E8853D172FC50C FC2A6074EEFB869779949D5BA9F7D69DA7D164E4FCCD4E7880B72311E46D2DF5 E7B1C6589310A7A32024832FF5F9D4B37239998E565B033D93CBA71798F65BA9 BC0DA236347D5D077AB720490C57422A84E06F1AE9FB29412E5BE70964C0C819 8A47CAB40B94EC52F816A8C719F7D4CB69F01D7A301702771BA08634BCDBE4F6 31CB72D421F2599824BD408CE71D9CE779AC734A1AD8AA18D3879EA6DE4A3FC9 E7662C00B29363D3E7423E6EC7E6CDD93237DA08A96E916C5B73D67536A1414D C72A1F20A111F6AB92B580F0489B685EF0C590992E571E56581173F31DF88832 F6068C43D7007FAD0E8BB794914DEBA0C96AF1EF14BA7FAD1FC862BA0BC852A2 0BA0D3538AC49B4790BBC398EFD5BC5B0E85D7059D3777EAF944EAC841CAAB31 1A67CA7EA02739A1613EB1D1876829DF54E2FD16488C23915A5FF80A08CC0A13 0485C57060A904A44BCA1A875A44B69DA34705AC2FC8E9A83B9F111E7F4C4500 924243C5B24C67821F571762467CB86A9B81F3EDA956354D42879F197E2402F6 1C2F2B98EAD6AE19AE7631D7A0E496DDB6F20EB6DD3C99D2E139F03DD5D4704C B426AEB9AA71390DE6F3D96889D65EC0BD3D82FA2C9317118A28952C13167A89 D406094517873CA18F38EDA7097603FFCA647B8875FFA97978365F5CF50A56B3 DB7EDE03545B2590B36D8B8D5F4DAEA8506526C2AA6570468DEB05760B030A07 3F3AF5B23112DE9C3C05DE75EA418BBF94C32179737E8F42799943887724CF8F 9DA5F11A69295F6EFFA6FA0AD279A1361B1D52109775436F2C7FF5BBBC77D4B8 F1107F2A08576CD1870509624B6E56D1678F9D33C81CD5087016FCC06FBC82F3 A09550C5E24E3DAE759DAC455A11B25FE72377DDAE9AA81AD9D4D63325AA0F58 A8A6EB71C3DC3B0F11FF3BED940AA262A73A3E1947DF15869592BAD2E9071C99 8653C0CF665D26E92CEB1B39FE9703D8EA8E7E60A1190D43F5A078703FF7E1C4 BEB4AC8DCF578AE64FAB5B16BD1D3A6FB58E85E38C86704C5ECE43748DC3B9BD 9EAE72DE3242FD7AE9DEDC87CD0ABD965FC0457674763F9A96D5A2E8975D14A9 99A1055BBC57DE58669ACE49B318150E973CDC4491051B2EE96F02FA8C492CE1 36F5F21D258C28F147FAC0956AB69985E9AED73C61A0252919C2120A2FAE0398 7763221425BB4FB02DBDC08EB6C53FBD9D29BF3B46981D4F03972879B310BAD9 B37477325D62387728F58C4B833F59B6D3C5AA09E34C014DB9CEAEA5A0B4F9FC B90C47C25FD0CF606556A77A16DAB902C3E7D34456163F1BCCE5775C84C260DD 3C20B3D09CD63E5AA2F385A86B0960BE1A9CEF16EAC4EBB7A1ED5BD27A149CDF FC33EED2613BD83B49865DF18BCD3FBDE81AF8F642987AB2AB93CCF12C77854C 76388C662CE0B36A5826C9E8415240560B83825CD41A901656224E7BB5693B50 6357EFE59D0F316C6971BDDCDB2867B10B09508441FF496AAB3E78CE3C410F48 5652156EC6730000DCE08BDC081E79C8D896227C0E80B953047493CCA7018608 736A9DB4CD0AA3E22F4D79D5DA275E33B37049289CF450AFE172E568BA36B7AD DFD595EF0586ABF0819FFFDD537B4E4C86DAF2BC95661384AD68CE96EF23269D D916E2912AEBC58037E89DED4BE0E2999BC98622DFE9E6F3CE27A8F6AD68E35A C23FBB9DC35881E93BCC13405AAD62EC4F6F883D0D254B123E115353D27AA577 9E3083252C6EA81CE951FD49C8C7EE2D51CADD4141EA7BF30C84F1CDBC1A2408 FB1C6743308E44DD0F6345DD0A96C8E17C5A8F57EA3303C640C47BA1B9089ACA 064B2397FD138E86EF5F8CBF4F0B2672B7E8B8607953830FDC1E659924C2EC67 0744C61266E71CC05BC9272B10E1B1ECF0D27341B4AA094D9175D3F985FBD734 AEA07422C72041A83B97A76CCBBE8D240AE30AC39E935C984BB9B6C6DA1A183A B1FB9B1E188FA39F22784E50F668F4B013EB31BBD4D54F02F112CEBA25654CA5 C2E214EDA83D60AC980D57DE311A99B6520643E617BA852BA5B946F679F01CAA 8EB637EE49D00C8659FEE6CFC5F0ACE844CCC3B837F2FE1DBFB4D8934368EE0E 71D7BC5F5D19089795A04D78E828AC0CD8AFF5BE3C3A0839BFC315B5E6FFC972 08A5EF5A0D74991E6D87E8C225700A2B662B50476E75EE9B355177756AF44FCE 526A6D8FABA37672BA0BF75B20F0E9D35F090CE686C95B4ABC8D3D88CCBBE109 3A11DAFB4205EBD81C81EAD61642BAB29EEB24CC93DC4DFB4C06086EA9BF56AA 38CCE1E30F5B95E189B8CD1920484960F4A2B39EDCB08E4CA3D88CEC2075541D EC2650A1145F87F0E24AF0951F795EE38E0C286A77C72BC3998F3F513B01797E 8AFABADA3671A7B86560ABFF0D585B8726C4EEB4E31653FDFC3AA4CC3358B90B AD7D6D39DE9B7009564270A6F9F9551E28D745C062D5AC6AC7A6F05C62796242 141E5F1841F2F7DBC2AD43C101B9966315AB7A8F68E4FC4B01BFF922CD157328 DACF4878EC8E975A30796C1477FBE6AAD9CD5F5C9AC269F5B92B5140B6FFB802 B929203ED3784C5A11A134C74EAA10D742A9F5BFFE2C8E688CE1B1ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMCSC10 %!PS-AdobeFont-1.1: CMCSC10 1.0 %%CreationDate: 1991 Aug 18 17:46:49 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMCSC10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMCSC10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 82 /R put dup 97 /a put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 110 /n put dup 114 /r put readonly def /FontBBox{14 -250 1077 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE 3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B 532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B 986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A30EB76029337 900ECFB1390CA5C0C3A04528044F266BA17BE487C79B94FAC6D6484684C5BFEA 87BCCC77D40AD11552035E95E3007126418ED49B68468B38A14E88E68A267B98 076F1C9769A5AFBC285E5B158EAC9F926F1D6C0B8F1D57D9C31D25AE27123518 9D2CD92E5689E0213089BD268DA5E47525CB8EABAA4B78A15AEA34705889AB3A FFB8953B5B3482E52BFA0940630ADF8C0AC2177D907324299EE980E850F203CD B627962F43D5A678C44243CDE97853BDC6AB45FD5C09AD274DAF89929F583CC9 CCC24BDFC68B92111055ABA5F26D2DC67C70906F71C2957701D65AE746A60C30 40E6CB24B97FCDAD0487AE38A201FBF0E41BABD2181981A71940F1E707F91E5D C8CA50CB16D8702D188E56D014D92F76CE0B52ABDB9110E32438D2BBF3E6A40B 7B005F10BB437812CAC6ED2996F7606DC962C4FDE207FF322782C343DF44CEC5 FF06A55C630C20E9AE1B0D1C5673753C43BA0767D65D1B451CC6380D8BB3C4DC 81E8FD8AA79BE993218686F29D3CD925566DD587F541A0DA1B1CC3BCEA2E6C7D 5E1016F6917A871F1BBAD96AF9E867735017119A381FCF33EB2D3E1E7093FD90 CDB0CED4818CFD9E201A03430CEC713620BE0D3254158931FB657C6AD4B2482A 0E7D070D7497892E9E942DF58E88CAF0C8221BF36BF7C435BF2C683A4A2EF4CB E85820A8AD3486155A40143011BA9D76297F46DEF69ECA4596D6E4CAABF84091 22A96A4BC78A8DD072FEB759A68A44BE1164638B6D952147EE3C628F9A022060 1D1941E73310943FA782532ABCCC88593FD63E7E2CECF6665C04DB48D641ABD3 AE1BB468638681E96394B9E7BED1D13E534B897DB90EA6EC706BAAE06BE2FEFF 1DFA5258113E9B4CD2D36655973864574E0E8D6291E48A8C62203F679B7ED838 6F7CBD523C2943ECA994CACE63D0C5B0E67F185086D619FE544ABA3EEC4F0E47 99F7795CD1DE83DD41EA1BCE69B153EA2479FC9048E13BA1813E52EA5D22AB5F FA37E1F9D6F59330404F24AD568FA2185CDCD945285717EF4719C4FE997D351A 57577E74EB86D8C701D4CEA146CC70759E02A66C411763B2A90F576494C4EBAB 8FC82605D4AB48B16E4BC48166858C6782F57DCE8DB723D5F8AF7F12425B5D07 72DB23C72B65526D4F901D883BDA578A71B540186C2A5F3207C06609E1739DF6 514C6B9E837DE430DA260AF122302F3BB25A7C9BA658223974F91300EBDF3D01 C9ADAABDB5E7A273312BA6EAE44E7D5F2F08A5922569389928DBB447E07E05A4 61001BB46D956581E40ABF9E6F080EA60DCF5F3367C43AA5F32BB5D0F5575F5F 6320605DA95A57F1B327A5C185400DF8A8563595C4255A3C1B7FB17B561B77AC 90D0E8261E1F7E4312C65B7B8329ED895E41820E2B875F2FB431A3146647424D D7C7E87D4F2973C211D4986FD88DDC101DE18D4753375431C8DA4B0ABE24487C FEEF3CFC1A5832134F7A803697B2682EBF32E365F643FBCCDBD772CFF83AC4A7 57846C9147A9702D20E73FF148E09B8A2F588A3C194875EBBD4D9877F37F99A4 DA4D6CD59FB32EA78435E3D9DB517A2B2F52410BADBB536785AFC1263F622441 AB57ACD5EE9253C6E5CA6194B2EBF4CA25D0F37CB21874504AAA5B5415442ED8 04F219028D9A7F6CAD67A424C744CC02FDA437CA9B247ED336630581880ED80C E0901B0497DE5187C598506C1B44019E7FDF5D65F3AFD60E0C0811A1151643E7 5225CA6777155945DB50338826510FCF1E69D8D4F4D67136CBF4F834F2D0D6B9 7F5A0E9D49CC642B654F759A3B6CC4D2FC923F6A4FCCDC6C9CF23CBD5013D4E0 BDC8098B638F98344E2A736EF3804C5FF590A13E0A3ADC09AC1B1C709AD8D639 A15E63B277B16B3DB586A09F9B9A4B56497998DF70747CE64B4E71FB4401AE00 A2CF7EA6BA56A718C29EDB6769DFF5955D35662A781E60372CAF5F105724D8CD 19C14C4DAA597EDD417FF9878C116B5855BAA4993156E6F7172CF37440B39E2F B568425A9443D8CE7D23460A64CD4541181D29E7D4BC25EFC1137780D2F300D3 4963EBE29DC9046A526FC78B938E7F59294EE30EDC13A3BB0508792D918F6129 69C4BDF8696C3A2788CAECCFC82344227D9A7ED587916B7ECBD0E7D3B3131A5E C40F52C8C8391C601386C642CE2BCE36389A4173A0B7A5E925CA731F7374D36D 931D1B6DD072770BBD542105136A61286C1F781DC6D0289C2A44F7D9AAE079BF 48D651C5E36B1DC44795D8B580E6A7B5B48EAFD3153306BC7A8C2D09E87432F0 FD7FA1E1A3577AA3A14EF320A7686D4350D4EF90777652CF06C2F21B71914A4C 2C3857B67581876767A9840E03B03D059951CF4B60C0234ECD3DB6F319DD0237 1E9F1F57D7B00FEF4D3E344B9AAE0F6680E4A647FBD30F10B0877DAB7144143D 48B8E775AC6F56C02B02D313FE0D3267F79DB5B3F6B2E340C2F8E5FBE165991B 9B27FCB3AE25DC0B65A1A932D13451D7850D9631F47AEF91ADF00F4E658FF7B5 17DB6243B1DBF7109D7B72E2517CBD6AE4409340C5E195C7F20BB96C9E1131CF 27E4BEBA57CE5D5542847AA2529CB6D0E83FA787022DBB1EC1A200AE5816E640 1CB33C040B5D0081877341876E22DE40FDEB596779121BDFF91F8FCE2E28A07A D7C9D30BB753B6761CB752EBEDA620A3412C4970AFF060AB8019109E31A48005 43D06D562DF6A21283E0BC6548559683508D14672C8DFEBFE83E0DA3860ADAA4 3741CCC98D895FBA2C207FB81B0C2E68543482DFF5F536E09B111895941CD94B 0324994193935B9682B9F2CEFE39EF35283666D055BF5764E707A58ADC9C7D3A 5B94483902DD7675C44EE6FBD4953299597C68FA74E3D2F513D3B6C9EC069BD7 D21DEB6579FFEFB90C66419FD4808EFD166AC899D9F5DBE1529FB44029F12B24 6BDECC7C93CD75D0A9BF5A74A3CF393438F221CD9E2C34B9EF9F245720A05CA3 491BBAFD9AACE5E43CB15A4FADA9AED90E290467E2C97CA539506B051C0F668C 86F353650D14DDCA8F80119FEEF7FF12BC09B7E87B2711C0296150F61B38AD2F E0F016438CA48D26AD95383F6DCB4C00E41684D3D374E274D56F8CBA69A3850B C53E9C2D5C8063296A3B572AB499C8CE6F216BAA9D46AEED9D5522721141B9F9 7C7826618763A279224B11D40023D793C675ADA20542DEBFCAF19E5E7EE79CC2 21F9DE8AE5A3859E3C3ED1DC84B0F299C38FED5C33A152CD0BF4AF8F4F699DB0 A776A9DFCBEBFEE460C3AB3A8417775D07E9F83FF9F6BFC3F2986D0FCC585230 C7955E0DEF1060719814BDD0CE320D06B75B797E7D0558C49A7FCE597CDBEBF4 6A07EE184EE71DDBB87180C28D44508F42EF1E3B42E6A8855D80E0AEAD045056 076B69BDDB999CEBC907C069173AF8572D7DA349AA8FBE46412EFE070973B6EF A21176C6948DB33724EAEB7F1786E5784A5D9AA039650042000406656FE3D640 16101B8E0B4A1F5D9200732799FC82B1AF5E27B2643E43D7B3805B9E31D1CB5B B4E7E9E818ED5A2B0639C7D8B3200FE229687FE65002CCF56D5E646900679B5D BE94992496DD43C9B694739E555864A6D99DCBBEDA8CDEE1F4EB9BFB1B2AA8A7 89FA43AEC162A98810B73B9040B946E0CEE744555B99AEE6FF1CDB1FBEE16474 9A3993F80473BA51298299D508D02DB0053F777D223E33A6A88A3CCB5C682883 9F81FB97F74686C44F7F55AB0D5079110206D35A9B4551A971DC9A53066DDE03 1A2F4295F49FA2801BC24F7929D2B794D485D4246FE7ED8BDC18E730E989D862 811C23453D8B0C8C41CA897CC6D48FF13A5A64F1E6296717644A70EC2D893CF4 E0DFD860D7CAD673D5D8F42F5DD03B7C6BCD3C376EF6142F2124F0780A37525E 4D005165006756DCCDD94B8E172B01 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont TeXDict begin 55387786 39139632 1000 600 600 (refcard.dvi) @start /Fa 134[30 30 40 30 31 22 23 22 1[31 28 31 46 17 30 1[17 31 28 18 25 31 25 31 28 13[31 2[37 9[36 23[17 20 17 44[{}29 41.511 /CMR5 rf /Fb 177[61 78[{}1 74.7198 /CMMI9 rf /Fc 135[35 1[35 41 25 31 32 1[39 39 43 1[20 35 1[24 1[35 24 35 39 35 35 39 3[24 1[24 45[27 29[69 1[45 13[{}24 74.7198 /CMTI9 rf /Fd 134[39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 11[39 39 39 39 1[39 39 39 39 39 3[39 1[39 39 39 39 39 39 1[39 39 39 39 1[39 11[39 39 39 39 9[39 33[{}51 74.7198 /CMTT9 rf /Fe 134[59 1[81 59 62 44 44 46 1[62 56 62 93 31 59 1[31 62 56 34 51 62 50 62 54 49[56 34[62 12[{}24 99.6264 /CMBX12 rf /Ff 242[77 13[{}1 74.7198 /CMSY9 rf /Fg 128[38 3[38 1[41 41 55 41 43 30 30 30 41 43 38 43 64 21 41 23 21 43 38 23 34 43 34 43 38 9[79 17[52 1[55 8[21 1[38 5[38 1[38 38 1[26 21 2[30 30 27[43 45 11[{}41 74.7198 /CMR9 rf /Fh 131[83 9[33 2[42 8[25 32[57 63 1[59 9[42 1[42 42 1[42 42 42 42 1[23 28 3[32 32 40[{}18 83.022 /CMR10 rf /Fi 141[104 3[106 7[92 96 108 102 1[106 14[138 12[128 143 135 133 66[{}12 172.188 /CMCSC10 rf end %%EndProlog %%BeginSetup %%Feature: *Resolution 600dpi TeXDict begin %%PaperSize: A4 @landscape end %%EndSetup %%Page: 1 1 TeXDict begin @landscape 1 0 bop -370 -104 a Fi(EDB)64 b(Reference)g(Card)49 31 y Fh(\(for)28 b(EDB)f(1.31)f(|)i(2008-05-26\)) 54 131 y Fg(Cop)n(yrigh)n(t)436 129 y(c)415 131 y Ff(\015)d Fg(2008)i(Eric)n(h)f(W\177)-38 b(alde)56 282 y Fe(con)m(trol)37 b(\014le)h(prop)s(erties)-411 410 y Fd(:display)27 b Fc(text-blo)l(ck-sp)l(e)l(c)-411 501 y Fd(:fields)g Fc(ve)l(ctor)-411 593 y Fd(:tagged-setup)i Fc(plist)-411 684 y Fd(:read-record)f Fc(function)-411 775 y Fd(:write-record)h Fc(function)-411 867 y Fd(:record-separator-function)i Fc(function)-411 958 y Fd(:record-terminator)f Fc(string-or-r)l(e)l(gexp-ve)l(ctor)-411 1049 y Fd(:record-separator)f Fc(string-or-r)l(e)l(gexp-ve)l(ct)q(or) -411 1141 y Fd(:field-separator)g Fc(string-or-r)l(e)l(gexp-ve)l(ct)q (or)-411 1232 y Fd(:substitution-separators)i Fc([fsep)c(rsep])-411 1323 y Fd(:substitutions)i Fc(ve)l(ctor)-411 1415 y Fd(:cruft)e Fc([[b)l(efr)l(e)l(c)h(aftr)l(e)l(c])g([b)l(e\017d)f(aft\015d]])-411 1506 y Fd(:data)g Fc(text-blo)l(ck-sp)l(e)l(c)-411 1597 y Fd(:choose-display)i Fc(function)-411 1689 y Fd(:before-display)g Fc(function)-411 1780 y Fd(:report)e Fc(text-blo)l(ck-sp)l(e)l(c)-411 1871 y Fd(:summary-format)i Fc(string)-411 1963 y Fd(:name)e Fc(string)-411 2054 y Fd(:first-change-function)k Fc(function)-411 2145 y Fd(:every-change-function)g Fc(function)-411 2237 y Fd(:field-order)d Fc(ve)l(ctor)-411 2328 y Fd(:locals)f Fc(ve)l(ctor)-411 2419 y Fd(:record-defaults)i Fc(function)113 2570 y Fe(displa)m(ysp)s(ec)39 b(options)-411 2699 y Fd(width=)p Fb(N)427 b Fg(maxim)n(um)25 b(\014eld)h(width)f(\(space)i (c)n(hars\))-411 2790 y Fd(height=)p Fb(N)388 b Fg(maxim)n(um)25 b(\014eld)h(heigh)n(t)f(\(lines\))-411 2881 y Fd(right-justify)215 b Fg(pad)25 b(with)h(spaces)h(on)f(the)f(left)-411 2973 y Fd(reachable)371 b Fg(editable)26 b(\014eld)-411 3064 y Fd(unreachable)293 b Fg(read-only)25 b(\014eld)274 3215 y Fe(builtin)38 b(t)m(yp)s(es)-411 3343 y Fg(displa)n(ysp)r(ecs:) 426 b Fd(integer)40 b(integer-or-nil)j(number)-411 3435 y(number-or-nil)f(yes-no)f(string)f(one-line-string)-411 3526 y(string-or-nil)i(nil-or-string)g(one-line-string-or-nil)-411 3709 y Fg(record\014eldt)n(yp)r(es:)306 b Fd(integer)40 b(integer-or-nil)j(number)-411 3800 y(number-or-nil)f(boolean)f(string) g(one-line-string)-411 3891 y(string-or-nil)h(nil-or-string)g (one-line-string-or-nil)p 1745 3998 4 4220 v 2125 -139 a Fe(en)m(tering/lea)m(ving)d(database)g(mo)s(de)1912 15 y Fg(connect)25 b(via)h(con)n(trol)h(\()p Fd(.edb)p Fg(\))f(\014le)358 b Fd(M-x)40 b(edb-interact)1912 106 y Fg(read)26 b(a)g(database)g(\014le)g(\(old)g(w)n(a)n(y\))367 b Fd(M-x)40 b(db-find-file)1912 198 y Fg(sa)n(v)n(e)26 b(the)f(database)h(\014le)g(to)g(disk)624 b Fd(C-x)39 b(C-s)1912 289 y Fg(sa)n(v)n(e)26 b(the)f(database)h(\014le)g(to)g (disk)624 b Fd(C-x)39 b(C-w)1912 380 y Fg(quit)25 b(editing)h(for)g(no) n(w)g(\(bury)f(bu\013ers\))434 b Fd(q)1912 472 y Fg(exit)25 b(edb)g(bu\013ers,)h(prompt)f(to)h(sa)n(v)n(e)g(c)n(hanges)236 b Fd(x)2580 658 y Fe(in)37 b(view)h(mo)s(de)1912 812 y Fg(go)26 b(to)g(next)f(record)1016 b Fd(n)1912 903 y Fg(go)26 b(to)g(previous)g(record)883 b Fd(p)1912 994 y Fg(go)26 b(to)g(\014rst)g(record)1030 b Fd(<,)39 b(M-<)1912 1086 y Fg(go)26 b(to)g(last)h(record)1043 b Fd(>,)39 b(M->)1912 1177 y Fg(jump)25 b(to)h(record)g Fd(N)1028 b(C-u)39 b(N)h(j)1912 1268 y Fg(go)26 b(to)g(next)f(screen)h(or)g (record)691 b Fd(SPC)1912 1360 y Fg(go)26 b(to)g(previous)g(screen)g (or)g(record)558 b Fd(DEL)1912 1451 y Fg(go)26 b(to)g(\014rst)g (\014eld)f(and)g(switc)n(h)h(to)g(edit)g(mo)r(de)258 b Fd(TAB,)40 b(C-n,)g(e)1912 1542 y Fg(go)26 b(to)g(last)h(\014eld)e (and)g(switc)n(h)h(to)g(edit)g(mo)r(de)271 b Fd(M-TAB,)40 b(C-p)1912 1634 y Fg(see)26 b(a)g(summary)g(of)g(all)h(records)637 b Fd(D,)39 b(H,)h(h)1912 1725 y Fg(in)n(v)n(ok)n(e)25 b(sort)h(in)n(terface)918 b Fd(S)1912 1816 y Fg(commit)26 b(curren)n(t)f(record)h(to)g(database)427 b Fd(RET)1912 1908 y Fg(undo)25 b(all)h(c)n(hanges)h(since)f(en)n(tering)g(the)f (record)185 b Fd(C-x)39 b(u)1912 1999 y Fg(undo)22 b(all)j(c)n(hanges)e (since)h(last)g(sa)n(ving)g(of)g(database)78 b Fd(C-x)39 b(r)1912 2090 y Fg(add)25 b(a)h(new)g(record)g(just)g(b)r(efore)h (curren)n(t)e(one)223 b Fd(a,)39 b(i)1912 2182 y Fg(cop)n(y)25 b(curren)n(t)g(record)h(and)f(go)i(to)f(the)f(cop)n(y)281 b Fd(c)1912 2273 y Fg(output)25 b(curren)n(t)g(record)h(to)f(another)h (database)171 b Fd(o)1912 2364 y Fg(delete)26 b(curren)n(t)f(record)896 b Fd(d,)39 b(k)1912 2456 y Fg(y)n(ank)24 b(most)j(recen)n(tly-deleted)d (record)457 b Fd(y)1912 2547 y Fg(generate)26 b(rep)r(ort)1080 b Fd(r)1912 2638 y Fg(set)26 b(summary)f(format)916 b Fd(F)1912 2729 y Fg(toggle)27 b Fd(truncate-lines)822 b(t)1912 2821 y Fg(new)26 b(data)g(displa)n(y)f(bu\013er)806 b Fd(+)2597 3007 y Fe(in)38 b(edit)f(mo)s(de)1912 3161 y Fg(return)25 b(to)h(view{mo)r(de)895 b Fd(C-c)39 b(C-c)1912 3252 y Fg(undo)25 b(c)n(hanges)h(to)g(curren)n(t)f(\014eld)616 b Fd(C-x)39 b(U)1912 3343 y Fg(go)26 b(to)g(next)f(\014eld)1084 b Fd(TAB)1912 3435 y Fg(go)26 b(to)g(previous)g(\014eld)951 b Fd(M-TAB)1912 3526 y Fg(go)26 b(to)g(\014rst)g(\014eld)1098 b Fd(M-<)1912 3617 y Fg(go)26 b(to)g(last)h(\014eld)1111 b Fd(M->)1912 3709 y Fg(go)26 b(to)g(next)f(line)h(or)g(\014eld)845 b Fd(C-n)1912 3800 y Fg(go)26 b(to)g(previous)g(line)g(or)g(\014eld)712 b Fd(C-p)1912 3891 y Fg(displa)n(y)25 b(help)h(for)g(curren)n(t)f (\014eld)h(in)f(ec)n(ho)h(area)214 b Fd(M-?)1912 3983 y Fg(searc)n(h)26 b(for)g(a)g(v)l(alue)g(in)f(the)h(curren)n(t)f (\014eld)351 b Fd(M-s)p 4068 3998 V 4907 -139 a Fe(sort)37 b(in)m(terface)4235 17 y Fg(en)n(ter)25 b(the)g(sort)h(in)n(terface)654 b Fd(M-x)40 b(db-sort)4235 108 y Fg(toggle)27 b(hidden-to-end)900 b Fd(t)4235 199 y Fg(kill)26 b(line)g(and)f(add)h(to)f(kill)h(stac)n(k) 625 b Fd(C-k)4235 291 y Fg(y)n(ank)24 b(lines)j(from)f(kill)g(stac)n(k) 750 b Fd(C-y)4235 382 y Fg(increasing)27 b(sort)f(order)905 b Fd(i)4235 473 y Fg(decreasing)26 b(sort)h(order)892 b Fd(d)4235 565 y Fg(increase)26 b(priorit)n(y)g(of)h(\014eld)e(at)h(p) r(oin)n(t)502 b Fd(M-p)4235 656 y Fg(decrease)26 b(priorit)n(y)g(of)g (\014eld)g(at)g(p)r(oin)n(t)489 b Fd(M-n)4235 747 y Fg(sp)r(ecify)26 b(an)g(ordering)g(function)654 b Fd(o)4235 839 y Fg(sp)r(ecify)26 b(a)g(sorting)h(function)743 b Fd(s)4235 930 y Fg(use)25 b(curren)n(t)g(ordering,)i(mak)n(e)f(db)e(default)326 b Fd(RET,)40 b(C-c)g(C-c)4235 1021 y Fg(use)25 b(curren)n(t)g (ordering,)i(mak)n(e)f(bu\013er)e(default)217 b Fd(A,)40 b(U)4235 1113 y Fg(use)25 b(curren)n(t)g(ordering)i(for)f(this)g(sort)g (only)326 b Fd(a,)40 b(u)4235 1204 y Fg(sort)26 b(according)h(to)e (\014eld)h(at)g(p)r(oin)n(t)564 b Fd(!)4235 1295 y Fg(ab)r(ort)26 b(sort)1258 b Fd(q)4235 1387 y Fg(clear)26 b(sort)g(order)g(and)g(exit) f(without)h(sorting)238 b Fd(c)4750 1574 y Fe(marking)39 b(and)f(hiding)4235 1730 y Fg(toggle)27 b(record)f(mark)n(ed/unmark)n (ed)512 b Fd(m)4235 1821 y Fg(toggle)27 b(record)f(hidden/unhidden)554 b Fd(O)4235 1913 y Fg(hide)25 b(all)i(unmark)n(ed)d(records,)j(clear)g (marks)5285 2004 y Fd(db-hide-unmarked-records)4235 2095 y Fg(mark)e(all)i(unhidden)d(records,)j(clear)f(hide)g(bits)5285 2187 y Fd(db-mark-unhidden-records)4235 2278 y Fg(clear)g(all)h(marks) 926 b Fd(db-unmark-all)4235 2369 y Fg(clear)26 b(all)h(hide)e(bits)839 b Fd(db-unhide-all)4235 2461 y Fg(goto)26 b(next)f(record,)h(ev)n(en)f (if)i(hidden)521 b Fd(M-n)4235 2552 y Fg(goto)26 b(previous)g(record,)g (ev)n(en)f(if)i(hidden)388 b Fd(M-p)4235 2643 y Fg(goto)26 b(next)f(mark)n(ed)g(record)768 b Fd(M-C-n)4235 2735 y Fg(goto)26 b(previous)g(mark)n(ed)f(record)635 b Fd(M-C-p)4235 2826 y Fg(enable/disable)27 b(hiding)702 b Fd(dbc-set-hide-p)4235 2917 y Fg(toggle)27 b(whether)e(hiding)h(is)g(in)g(e\013ect)494 b Fd(M-o)4235 3009 y Fg(toggle)27 b(sho)n(w)f(hidden)f(in)g(summary)526 b Fd(M-C-o)4700 3435 y Fg(Cop)n(yrigh)n(t)5082 3433 y(c)5061 3435 y Ff(\015)25 b Fg(2008)i(Eric)n(h)f(W\177)-38 b(alde)4353 3485 y Fa(P)o(ermission)16 b(is)h(gran)o(ted)h(to)g(mak)o(e)e(and)h (distribute)i(v)o(erbatim)e(copies)g(of)h(this)f(refcard)4235 3534 y(pro)o(vided)26 b(the)h(cop)o(yrigh)o(t)g(notice)h(and)e(this)h (p)q(ermission)f(notice)i(are)f(preserv)o(ed)h(on)e(all)4235 3584 y(copies.)4353 3634 y(P)o(ermission)c(is)g(gran)o(ted)h(to)g(cop)o (y)g(and)g(distribute)g(mo)q(dified)g(v)o(ersions)f(of)h(this)f(ref-) 4235 3684 y(card)15 b(under)h(the)f(conditions)g(for)h(v)o(erbatim)e (cop)o(ying,)h(pro)o(vided)g(that)h(the)f(en)o(tire)h(resulting)4235 3734 y(deriv)o(ed)23 b(w)o(ork)f(is)g(distributed)i(under)f(the)h (terms)f(of)g(a)g(p)q(ermission)f(notice)i(iden)o(tical)f(to)4235 3783 y(this)c(one.)4353 3833 y(P)o(ermission)26 b(is)h(gran)o(ted)i(to) e(cop)o(y)g(and)h(distribute)g(translations)h(of)e(this)g(man)o(ual) 4235 3883 y(in)o(to)20 b(another)i(language,)f(under)g(the)g(ab)q(o)o (v)o(e)f(conditions)h(for)g(mo)q(dified)f(v)o(ersions,)f(except)4235 3933 y(that)i(this)e(p)q(ermission)h(notice)h(ma)o(y)e(b)q(e)h(stated)h (in)e(a)h(translation)h(appro)o(v)o(ed)g(b)o(y)d(the)j(F)l(ree)4235 3983 y(Soft)o(w)o(are)f(F)l(oundation.)p eop end %%Trailer userdict /end-hook known{end-hook}if %%EOF edb-1.31/doc/refcard.version.tex0000644000175000017500000000010211016452257014741 0ustar ttnttn\def\versionnumber{1.31} \def\year{2008} \def\updated{2008-05-26} edb-1.31/doc/texinfo.tex0000644000175000017500000070337610531031126013337 0ustar ttnttn% texinfo.tex -- TeX macros to handle Texinfo files. % % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % \def\texinfoversion{2006-02-13.16} % % Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free % Software Foundation, Inc. % % This texinfo.tex 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, or (at % your option) any later version. % % This texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write % to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, % Boston, MA 02110-1301, USA. % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. (This has been our intent since Texinfo was invented.) % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % http://www.gnu.org/software/texinfo/ (the Texinfo home page), or % ftp://tug.org/tex/texinfo.tex % (and all CTAN mirrors, see http://www.ctan.org). % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % Send bug reports to bug-texinfo@gnu.org. Please include including a % complete document in each bug report with which we can reproduce the % problem. Patches are, of course, greatly appreciated. % % To process a Texinfo manual with TeX, it's most reliable to use the % texi2dvi shell script that comes with the distribution. For a simple % manual foo.texi, however, you can get away with this: % tex foo.texi % texindex foo.?? % tex foo.texi % tex foo.texi % dvips foo.dvi -o # or whatever; this makes foo.ps. % The extra TeX runs get the cross-reference information correct. % Sometimes one run after texindex suffices, and sometimes you need more % than two; texi2dvi does it as many times as necessary. % % It is possible to adapt texinfo.tex for other languages, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is http://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} % If in a .fmt file, print the version number % and turn on active characters that we couldn't do earlier because % they might have appeared in the input file name. \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} \message{Basics,} \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros whose names we will redefine. \let\ptexb=\b \let\ptexbullet=\bullet \let\ptexc=\c \let\ptexcomma=\, \let\ptexdot=\. \let\ptexdots=\dots \let\ptexend=\end \let\ptexequiv=\equiv \let\ptexexclam=\! \let\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexnewwrite\newwrite \let\ptexnoindent=\noindent \let\ptexplus=+ \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexstar=\* \let\ptext=\t % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. % \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % Set up fixed words for English if not already set. \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\fi \ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi \ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi \ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi \ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi \ifx\putwordof\undefined \gdef\putwordof{of}\fi \ifx\putwordon\undefined \gdef\putwordon{on}\fi \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi \ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi \ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi % \ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi \ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi \ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi \ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi \ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi \ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi \ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi \ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi \ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi \ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi \ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi \ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi % \ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi \ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi \ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % Since the category of space is not known, we have to be careful. \chardef\spacecat = 10 \def\spaceisspace{\catcode`\ =\spacecat} % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). % \def\finalout{\overfullrule=0pt} % @| inserts a changebar to the left of the current line. It should % surround any changed text. This approach does *not* work if the % change spans more than two lines of output. To handle that, we would % have adopt a much more difficult approach (putting marks into the main % vertical list for the beginning and end of each change). % \def\|{% % \vadjust can only be used in horizontal mode. \leavevmode % % Append this vertical mode material after the current line in the output. \vadjust{% % We want to insert a rule with the height and depth of the current % leading; that is exactly what \strutbox is supposed to record. \vskip-\baselineskip % % \vadjust-items are inserted at the left edge of the type. So % the \llap here moves out into the left-hand margin. \llap{% % % For a thicker or thinner bar, change the `1pt'. \vrule height\baselineskip width1pt % % This is the space between the bar and the text. \hskip 12pt }% }% } % Sometimes it is convenient to have everything in the transcript file % and nothing on the terminal. We don't just call \tracingall here, % since that produces some useless output on the terminal. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\undefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % For @cropmarks command. % Do @cropmarks to get crop marks. % \newif\ifcropmarks \let\cropmarks = \cropmarkstrue % % Dimensions to add cropmarks at corners. % Added by P. A. MacKay, 12 Nov. 1986 % \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines \newdimen\cornerlong \cornerlong=1pc \newdimen\cornerthick \cornerthick=.3pt \newdimen\topandbottommargin \topandbottommargin=.75in % Main output routine. \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. Note that \pagecontents % does insertions, but you have to call it yourself. \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% % {% % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \indexdummies % don't expand commands in the output. \normalturnoffactive % \ in index entries must not stay \, e.g., if % the page break happens to be in the middle of an example. % We don't want .vr (or whatever) entries like this: % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\tt \backslashcurfont }acronym} \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \ifcropmarks \vbox to \outervsize\bgroup \hsize = \outerhsize \vskip-\topandbottommargin \vtop to0pt{% \line{\ewtop\hfil\ewtop}% \nointerlineskip \line{% \vbox{\moveleft\cornerthick\nstop}% \hfill \vbox{\moveright\cornerthick\nstop}% }% \vss}% \vskip\topandbottommargin \line\bgroup \hfil % center the page within the outer (page) hsize. \ifodd\pageno\hskip\bindingoffset\fi \vbox\bgroup \fi % \unvbox\headlinebox \pagebody{#1}% \ifdim\ht\footlinebox > 0pt % Only leave this space if the footline is nonempty. % (We lessened \vsize for it in \oddfootingxxx.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 2\baselineskip \unvbox\footlinebox \fi % \ifcropmarks \egroup % end of \vbox\bgroup \hfil\egroup % end of (centering) \line\bgroup \vskip\topandbottommargin plus1fill minus1fill \boxmaxdepth = \cornerthick \vbox to0pt{\vss \line{% \vbox{\moveleft\cornerthick\nsbot}% \hfill \vbox{\moveright\cornerthick\nsbot}% }% \nointerlineskip \line{\ewbot\hfil\ewbot}% }% \egroup % \vbox from first cropmarks clause \fi }% end of \shipout\vbox }% end of group with \indexdummies \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) \ifvoid\margin\else % marginal info is present \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1 \unvbox#1 \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} } % Here are the rules for the cropmarks. Note that they are % offset so that the space between them is truly \outerhsize or \outervsize % (P. A. MacKay, 12 November, 1986) % \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} \def\nstop{\vbox {\hrule height\cornerthick depth\cornerlong width\cornerthick}} \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} \def\nsbot{\vbox {\hrule height\cornerlong depth\cornerthick width\cornerthick}} % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\next{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % We cannot use \next here, as it holds the macro to run; % thus we reuse \temp. \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \next. % (Similarily, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\next\expandafter{#1}} % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} % % Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my % favourite TeX trick. --kasal, 16nov03 \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. % \gdef\sepspaces{\obeyspaces\let =\tie} % If an index command is used in an @example environment, any spaces % therein should become regular spaces in the raw index file, not the % expansion of \tie (\leavevmode \penalty \@M \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as enviroments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At runtime, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Evironment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty out of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} %% Simple single-character @ commands % @@ prints an @ % Kludge this until the fonts are right (grr). \def\@{{\tt\char64}} % This is turned off because it was never documented % and you can use @w{...} around a quote to suppress ligatures. %% Define @` and @' to be the same as ` and ' %% but suppressing ligatures. %\def\`{{`}} %\def\'{{'}} % Used to generate quoted braces. \def\mylbrace {{\tt\char123}} \def\myrbrace {{\tt\char125}} \let\{=\mylbrace \let\}=\myrbrace \begingroup % Definitions to produce \{ and \} commands for indices, % and @{ and @} for the aux/toc files. \catcode`\{ = \other \catcode`\} = \other \catcode`\[ = 1 \catcode`\] = 2 \catcode`\! = 0 \catcode`\\ = \other !gdef!lbracecmd[\{]% !gdef!rbracecmd[\}]% !gdef!lbraceatcmd[@{]% !gdef!rbraceatcmd[@}]% !endgroup % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \c \let\dotaccent = \. \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \t \let\ubaraccent = \b \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ptexi \else\ifx\temp\jmacro \j \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=1000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% \kern-.15em \TeX } % Be sure we're in horizontal mode when doing a tie, since we make space % equivalent to this in @example-like environments. Otherwise, a space % at the beginning of a line will start with \penalty -- and % since \penalty is valid in vertical mode, we'd end up putting the % penalty on the vertical list instead of in the new paragraph. {\catcode`@ = 11 % Avoid using \@M directly, because that causes trouble % if the definition is written into an index file. \global\let\tiepenalty = \@M \gdef\tie{\leavevmode\penalty\tiepenalty\ } } % @: forces normal size whitespace following. \def\:{\spacefactor=1000 } % @* forces a line break. \def\*{\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} % @! is an end-of-sentence bang. \def\!{!\spacefactor=\endofsentencespacefactor\space} % @? is an end-of-sentence query. \def\?{?\spacefactor=\endofsentencespacefactor\space} % @frenchspacing on|off says whether to put extra space after punctuation. % \def\onword{on} \def\offword{off} % \parseargdef\frenchspacing{% \def\temp{#1}% \ifx\temp\onword \plainfrenchspacing \else\ifx\temp\offword \plainnonfrenchspacing \else \errhelp = \EMsimple \errmessage{Unknown @frenchspacing option `\temp', must be on/off}% \fi\fi } % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. \def\w#1{\leavevmode\hbox{#1}} % @group ... @end group forces ... to be all on one page, by enclosing % it in a TeX vbox. We use \vtop instead of \vbox to construct the box % to keep its height that of a normal line. According to the rules for % \topskip (p.114 of the TeXbook), the glue inserted is % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % Do @comment since we are called inside an environment such as % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo % manual), we don't worry about eating any user text. \comment } % % The \vtop produces a box with normal height and large depth; thus, TeX puts % \baselineskip glue before it, and (when the next line of text is done) % \lineskip glue after it. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \pageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\pageheight \page \fi \fi \box\groupbox \prevdepth = \dimen1 \checkinserts } % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. % \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} % @need space-in-mils % forces a page break if there is not space-in-mils remaining. \newdimen\mil \mil=0.001in % Old definition--didn't work. %\parseargdef\need{\par % %% This method tries to make TeX break the page naturally %% if the depth of the box does not fit. %{\baselineskip=0pt% %\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak %\prevdepth=-1000pt %}} \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\vfil}% % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which % almost-but-not-quite fill up a page, TeX will have a hard time doing % good page breaking, for example.) However, I could not construct an % example where a page broke at this \penalty; if it happens in a real % document, then we can reconsider our strategy. \penalty9999 % % Back up by the size of the box, whether we did a page break or not. \kern -#1\mil % % Do not allow a page break right after this kern. \nobreak \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @page forces the start of a new page. % \def\page{\par\vfill\supereject} % @exdent text.... % outputs text on separate line in roman font, starting at standard page margin % This records the amount of indent in the innermost environment. % That's how much \exdent should take out. \newskip\exdentamount % This defn is used inside fill environments such as @defun. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @include file insert text of that file as input. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable \def\temp{\input #1 }% \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\next\centerH \else \let\next\centerV \fi \next{\hfil \ignorespaces#1\unskip \hfil}% } \def\centerH#1{% {% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }% } \def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} % @sp n outputs n lines of vertical space \parseargdef\sp{\vskip #1\baselineskip} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment \def\comment{\begingroup \catcode`\^^M=\other% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \commentxxx} {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} \let\c=\comment % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent{% \restorefirstparagraphindent \indent }% \gdef\noindent{% \restorefirstparagraphindent \noindent }% \global\everypar = {% \kern -\parindent \restorefirstparagraphindent }% } \gdef\restorefirstparagraphindent{% \global \let \indent = \ptexindent \global \let \noindent = \ptexnoindent \global \everypar = {}% } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode`\_ = \active \gdef\mathunderscore{% \catcode`\_=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a \ character. % FYI, plain.tex uses \\ as a temporary control sequence (why?), but % this is not advertised and we don't care. Texinfo does not % otherwise define @\. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \tex \mathunderscore \let\\ = \mathbackslash \mathactive $\finishmath } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus } } % @bullet and @minus need the same treatment as @math, just above. \def\bullet{$\ptexbullet$} \def\minus{$-$} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in a typewriter % font as three actual period characters. % \def\dots{% \leavevmode \hbox to 1.5em{% \hskip 0pt plus 0.25fil .\hfil.\hfil.% \hskip 0pt plus 0.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=\endofsentencespacefactor } % @comma{} is so commas can be inserted into text without messing up % Texinfo's parsing. % \let\comma = , % @refill is a no-op. \let\refill=\relax % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate (before @setfilename). % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. \def\setfilename{% \fixbackslash % Turn off hack to swallow `\input texinfo'. \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi % \openindices needs to do some work in any case. \openindices \let\setfilename=\comment % Ignore extra @setfilename cmds. % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. \openin 1 texinfo.cnf \ifeof 1 \else \input texinfo.cnf \fi \closein 1 % \comment % Ignore the actual filename. } % Called from \setfilename. % \def\openindices{% \newindex{cp}% \newcodeindex{fn}% \newcodeindex{vr}% \newcodeindex{tp}% \newcodeindex{ky}% \newcodeindex{pg}% } % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as \undefined, % borrowed from ifpdf.sty. \ifx\pdfoutput\undefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % PDF uses PostScript string constants for the names of xref targets, % for display in the outlines, and in other places. Thus, we have to % double any backslashes. Otherwise, a name like "\node" will be % interpreted as a newline (\n), followed by o, d, e. Not good. % http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html % (and related messages, the final outcome is that it is up to the TeX % user to double the backslashes and otherwise make the string valid, so % that's what we do). % double active backslashes. % {\catcode`\@=0 \catcode`\\=\active @gdef@activebackslashdouble{% @catcode`@\=@active @let\=@doublebackslash} } % To handle parens, we must adopt a different approach, since parens are % not active characters. hyperref.dtx (which has the same problem as % us) handles it with this amazing macro to replace tokens. I've % tinkered with it a little for texinfo, but it's definitely from there. % % #1 is the tokens to replace. % #2 is the replacement. % #3 is the control sequence with the string. % \def\HyPsdSubst#1#2#3{% \def\HyPsdReplace##1#1##2\END{% ##1% \ifx\\##2\\% \else #2% \HyReturnAfterFi{% \HyPsdReplace##2\END }% \fi }% \xdef#3{\expandafter\HyPsdReplace#3#1\END}% } \long\def\HyReturnAfterFi#1\fi{\fi#1} % #1 is a control sequence in which to do the replacements. \def\backslashparens#1{% \xdef#1{#1}% redefine it as its expansion; the definition is simply % \lastnode when called from \setref -> \pdfmkdest. \HyPsdSubst{(}{\realbackslash(}{#1}% \HyPsdSubst{)}{\realbackslash)}{#1}% } \ifpdf \input pdfcolor \pdfcatalog{/PageMode /UseOutlines}% \def\dopdfimage#1#2#3{% \def\imagewidth{#2}% \def\imageheight{#3}% % without \immediate, pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifx\empty\imagewidth\else width \imagewidth \fi \ifx\empty\imageheight\else height \imageheight \fi \ifnum\pdftexversion<13 #1.pdf% \else {#1.pdf}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} \def\pdfmkdest#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \atdummies \activebackslashdouble \def\pdfdestname{#1}% \backslashparens\pdfdestname \pdfdest name{\pdfdestname} xyz% }}% % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1}% % \let\linkcolor = \Blue % was Cyan, but that seems light? \def\endlink{\Black\pdfendlink} % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text, which is what will be displayed in the % outline by the pdf viewer. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node text, % which might be empty if this toc entry had no corresponding node. % #4 is the page number % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. \def\pdfoutlinedest{#3}% \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}% \else % Doubled backslashes in the name. {\activebackslashdouble \xdef\pdfoutlinedest{#3}% \backslashparens\pdfoutlinedest}% \fi % % Also double the backslashes in the display string. {\activebackslashdouble \xdef\pdfoutlinetext{#1}% \backslashparens\pdfoutlinetext}% % \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% \begingroup % Thanh's hack / proper braces in bookmarks \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace % % Read toc silently, to get counts of subentries for \pdfoutline. \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \def\thissecnum{0}% \def\thissubsecnum{0}% }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \def\thissubsecnum{0}% }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \def\thischapnum{0}% \def\thissecnum{0}% \def\thissubsecnum{0}% % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \readdatafile{toc}% % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % xx to do this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Right % now, I guess we'll just let the pdf reader have its way. \indexnofonts \setupdatafile \catcode`\\=\active \otherbackslash \input \jobname.toc \endgroup } % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \ifx\p\space\else\addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \fi \nextsp} \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable \leavevmode\Red \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \linkcolor #1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\linkcolor = \relax \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput \message{fonts,} % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname ten#1\endcsname % change the current font } % Select #1 fonts with the current style. % \def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} \let\li = \sf % Sometimes we call it \li, not \sf. % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % Default leading. \newdimen\textleading \textleading = 13.2pt % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. % \def\lineskipfactor{.08333} \def\strutheightpercent{.70833} \def\strutdepthpercent {.29167} % \def\setleading#1{% \normalbaselineskip = #1\relax \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % Set the font macro #1 to the font named #2, adding on the % specified font prefix (normally `cm'). % #3 is the font's design size, #4 is a scale factor \def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\undefined \def\fontprefix{cm} \fi % Support font families that don't use the same naming scheme as CM. \def\rmshape{r} \def\rmbshape{bx} %where the normal face is bold \def\bfshape{b} \def\bxshape{bx} \def\ttshape{tt} \def\ttbshape{tt} \def\ttslshape{sltt} \def\itshape{ti} \def\itbshape{bxti} \def\slshape{sl} \def\slbshape{bxsl} \def\sfshape{ss} \def\sfbshape{ss} \def\scshape{csc} \def\scbshape{csc} % Text fonts (11.2pt, magstep1). \def\textnominalsize{11pt} \edef\mainmagstep{\magstephalf} \setfont\textrm\rmshape{10}{\mainmagstep} \setfont\texttt\ttshape{10}{\mainmagstep} \setfont\textbf\bfshape{10}{\mainmagstep} \setfont\textit\itshape{10}{\mainmagstep} \setfont\textsl\slshape{10}{\mainmagstep} \setfont\textsf\sfshape{10}{\mainmagstep} \setfont\textsc\scshape{10}{\mainmagstep} \setfont\textttsl\ttslshape{10}{\mainmagstep} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1} \setfont\deftt\ttshape{10}{\magstep1} \setfont\defttsl\ttslshape{10}{\magstep1} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000} \setfont\smalltt\ttshape{9}{1000} \setfont\smallbf\bfshape{10}{900} \setfont\smallit\itshape{9}{1000} \setfont\smallsl\slshape{9}{1000} \setfont\smallsf\sfshape{9}{1000} \setfont\smallsc\scshape{10}{900} \setfont\smallttsl\ttslshape{10}{900} \font\smalli=cmmi9 \font\smallsy=cmsy9 % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000} \setfont\smallertt\ttshape{8}{1000} \setfont\smallerbf\bfshape{10}{800} \setfont\smallerit\itshape{8}{1000} \setfont\smallersl\slshape{8}{1000} \setfont\smallersf\sfshape{8}{1000} \setfont\smallersc\scshape{10}{800} \setfont\smallerttsl\ttslshape{10}{800} \font\smalleri=cmmi8 \font\smallersy=cmsy8 % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3} \setfont\titleit\itbshape{10}{\magstep4} \setfont\titlesl\slbshape{10}{\magstep4} \setfont\titlett\ttbshape{12}{\magstep3} \setfont\titlettsl\ttslshape{10}{\magstep4} \setfont\titlesf\sfbshape{17}{\magstep1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\authorrm{\secrm} \def\authortt{\sectt} % Chapter (and unnumbered) fonts (17.28pt). \def\chapnominalsize{17pt} \setfont\chaprm\rmbshape{12}{\magstep2} \setfont\chapit\itbshape{10}{\magstep3} \setfont\chapsl\slbshape{10}{\magstep3} \setfont\chaptt\ttbshape{12}{\magstep2} \setfont\chapttsl\ttslshape{10}{\magstep3} \setfont\chapsf\sfbshape{17}{1000} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 % Section fonts (14.4pt). \def\secnominalsize{14pt} \setfont\secrm\rmbshape{12}{\magstep1} \setfont\secit\itbshape{10}{\magstep2} \setfont\secsl\slbshape{10}{\magstep2} \setfont\sectt\ttbshape{12}{\magstep1} \setfont\secttsl\ttslshape{10}{\magstep2} \setfont\secsf\sfbshape{12}{\magstep1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 % Subsection fonts (13.15pt). \def\ssecnominalsize{13pt} \setfont\ssecrm\rmbshape{12}{\magstephalf} \setfont\ssecit\itbshape{10}{1315} \setfont\ssecsl\slbshape{10}{1315} \setfont\ssectt\ttbshape{12}{\magstephalf} \setfont\ssecttsl\ttslshape{10}{1315} \setfont\ssecsf\sfbshape{12}{\magstephalf} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 % Reduced fonts for @acro in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000} \setfont\reducedtt\ttshape{10}{1000} \setfont\reducedbf\bfshape{10}{1000} \setfont\reducedit\itshape{10}{1000} \setfont\reducedsl\slshape{10}{1000} \setfont\reducedsf\sfshape{10}{1000} \setfont\reducedsc\scshape{10}{1000} \setfont\reducedttsl\ttslshape{10}{1000} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. Since % texinfo doesn't allow for producing subscripts and superscripts except % in the main text, we don't bother to reset \scriptfont and % \scriptscriptfont (which would also require loading a lot more fonts). % \def\resetmathfonts{% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf \textfont\ttfam=\tentt \textfont\sffam=\tensf } % The font-changing commands redefine the meanings of \tenSTYLE, instead % of just \STYLE. We do this because \STYLE needs to also set the % current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire % \tenSTYLE to set the current font. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used in % the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \def\textfonts{% \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl \def\curfontsize{text}% \def\lsize{reduced}\def\lllsize{smaller}% \resetmathfonts \setleading{\textleading}} \def\titlefonts{% \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy \let\tenttsl=\titlettsl \def\curfontsize{title}% \def\lsize{chap}\def\lllsize{subsec}% \resetmathfonts \setleading{25pt}} \def\titlefont#1{{\titlefonts\rm #1}} \def\chapfonts{% \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl \def\curfontsize{chap}% \def\lsize{sec}\def\lllsize{text}% \resetmathfonts \setleading{19pt}} \def\secfonts{% \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl \def\curfontsize{sec}% \def\lsize{subsec}\def\lllsize{reduced}% \resetmathfonts \setleading{16pt}} \def\subsecfonts{% \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl \def\curfontsize{ssec}% \def\lsize{text}\def\lllsize{small}% \resetmathfonts \setleading{15pt}} \let\subsubsecfonts = \subsecfonts \def\reducedfonts{% \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy \let\tenttsl=\reducedttsl \def\curfontsize{reduced}% \def\lsize{small}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallfonts{% \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy \let\tenttsl=\smallttsl \def\curfontsize{small}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallerfonts{% \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy \let\tenttsl=\smallerttsl \def\curfontsize{smaller}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{9.5pt}} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % % I wish the USA used A4 paper. % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \textfonts \rm % Define these so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000} \setfont\shortcontbf\bfshape{10}{\magstep1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000} \setfont\shortconttt\ttshape{12}{1000} %% Add scribe-like font environments, plus @l for inline lisp (usually sans %% serif) and @ii for TeX italic % \smartitalic{ARG} outputs arg in italics, followed by an italic correction % unless the following character is such as not to need one. \def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else \ptexslash\fi\fi\fi} \def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} \def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} % like \smartslanted except unconditionally uses \ttsl. % @var is set to this for defun arguments. \def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} % like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitalicx} \let\i=\smartitalic \let\slanted=\smartslanted \let\var=\smartslanted \let\dfn=\smartslanted \let\emph=\smartitalic % @b, explicit bold. \def\b#1{{\bf #1}} \let\strong=\b % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. % \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \chardef\colonChar = `\: \chardef\commaChar = `\, \chardef\dotChar = `\. \chardef\exclamChar= `\! \chardef\questChar = `\? \chardef\semiChar = `\; % \catcode`@=11 \def\plainfrenchspacing{% \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m \def\endofsentencespacefactor{1000}% for @. and friends } \def\plainnonfrenchspacing{% \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 \def\endofsentencespacefactor{3000}% for @. and friends } \catcode`@=\other \def\endofsentencespacefactor{3000}% default \def\t#1{% {\tt \rawbackslash \plainfrenchspacing #1}% \null } \def\samp#1{`\tclose{#1}'\null} \setfont\keyrm\rmshape{8}{1000} \font\keysy=cmsy9 \def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% \vbox{\hrule\kern-0.4pt \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% \kern-0.4pt\hrule}% \kern-.06em\raise0.4pt\hbox{\angleright}}}} % The old definition, with no lozenge: %\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} \def\ctrl #1{{\tt \rawbackslash \hat}#1} % @file, @option are the same as @samp. \let\file=\samp \let\option=\samp % @code is a modification of @t, % which makes spaces the same size as normal in the surrounding text. \def\tclose#1{% {% % Change normal interword space to be same as for the current font. \spaceskip = \fontdimen2\font % % Switch to typewriter. \tt % % But `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % % Turn off hyphenation. \nohyphenation % \rawbackslash \plainfrenchspacing #1% }% \null } % We *must* turn on hyphenation at `-' and `_' in @code. % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. % Unfortunately, TeX uses one parameter (\hyphenchar) to control % both hyphenation at - and hyphenation within words. % We must therefore turn them both off (\tclose does that) % and arrange explicitly to hyphenate at a dash. % -- rms. { \catcode`\-=\active \catcode`\_=\active % \global\def\code{\begingroup \catcode`\-=\active \catcode`\_=\active \ifallowcodebreaks \let-\codedash \let_\codeunder \else \let-\realdash \let_\realunder \fi \codex } } \def\realdash{-} \def\codedash{-\discretionary{}{}{}} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } \def\codex #1{\tclose{#1}\endgroup} % An additional complication: the above will allow breaks after, e.g., % each of the four underscores in __typeof__. This is undesirable in % some manuals, especially if they don't have long identifiers in % general. @allowcodebreaks provides a way to control this. % \newif\ifallowcodebreaks \allowcodebreakstrue \def\keywordtrue{true} \def\keywordfalse{false} \parseargdef\allowcodebreaks{% \def\txiarg{#1}% \ifx\txiarg\keywordtrue \allowcodebreakstrue \else\ifx\txiarg\keywordfalse \allowcodebreaksfalse \else \errhelp = \EMsimple \errmessage{Unknown @allowcodebreaks option `\txiarg'}% \fi\fi } % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), % `example' (@kbd uses ttsl only inside of @example and friends), % or `code' (@kbd uses normal tty font always). \parseargdef\kbdinputstyle{% \def\txiarg{#1}% \ifx\txiarg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\txiarg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\txiarg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle option `\txiarg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct.' \kbdinputstyle distinct \def\xkey{\key} \def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\look}}\fi \else{\tclose{\kbdfont\look}}\fi} % For @indicateurl, @env, @command quotes seem unnecessary, so use \code. \let\indicateurl=\code \let\env=\code \let\command=\code % @uref (abbreviation for `urlref') takes an optional (comma-separated) % second argument specifying the text to display and an optional third % arg as text to display instead of (rather than in addition to) the url % itself. First (mandatory) arg is the url. Perhaps eventually put in % a hypertex \special here. % \def\uref#1{\douref #1,,,\finish} \def\douref#1,#2,#3,#4\finish{\begingroup \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url \fi \else \code{#1}% only url given, so show it \fi \fi \endlink \endgroup} % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \let\email=\uref \fi % Check if we are currently using a typewriter font. Since all the % Computer Modern typewriter fonts have zero interword stretch (and % shrink), and it is reasonable to expect all typewriter fonts to have % this property, we can check that font parameter. % \def\ifmonospace{\ifdim\fontdimen3\font=0pt } % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. % \def\dmn#1{\thinspace #1} \def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} % @l was never documented to mean ``switch to the Lisp font'', % and it is not used as such in any manual I can find. We need it for % Polish suppressed-l. --karl, 22sep96. %\def\l#1{{\li #1}\null} % Explicit font changes: @r, @sc, undocumented @ii. \def\r#1{{\rm #1}} % roman font \def\sc#1{{\smallcaps#1}} % smallcaps font \def\ii#1{{\it #1}} % italic font % @acronym for "FBI", "NATO", and the like. % We print this one point size smaller, since it's intended for % all-uppercase. % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\selectfonts\lsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi } % @abbr for "Comput. J." and the like. % No font change, but don't do end-of-sentence spacing. % \def\abbr#1{\doabbr #1,,\finish} \def\doabbr#1,#2,#3\finish{% {\plainfrenchspacing #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi } % @pounds{} is a sterling sign, which Knuth put in the CM italic font. % \def\pounds{{\it\$}} % @euro{} comes from a separate font, depending on the current style. % We use the free feym* fonts from the eurosym package by Henrik % Theiling, which support regular, slanted, bold and bold slanted (and % "outlined" (blackboard board, sort of) versions, which we don't need). % It is available from http://www.ctan.org/tex-archive/fonts/eurosym. % % Although only regular is the truly official Euro symbol, we ignore % that. The Euro is designed to be slightly taller than the regular % font height. % % feymr - regular % feymo - slanted % feybr - bold % feybo - bold slanted % % There is no good (free) typewriter version, to my knowledge. % A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. % Hmm. % % Also doesn't work in math. Do we need to do math with euro symbols? % Hope not. % % \def\euro{{\eurofont e}} \def\eurofont{% % We set the font at each command, rather than predefining it in % \textfonts and the other font-switching commands, so that % installations which never need the symbol don't have to have the % font installed. % % There is only one designed size (nominal 10pt), so we always scale % that to the current nominal size. % % By the way, simply using "at 1em" works for cmr10 and the like, but % does not work for cmbx10 and other extended/shrunken fonts. % \def\eurosize{\csname\curfontsize nominalsize\endcsname}% % \ifx\curfontstyle\bfstylename % bold: \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize \else % regular: \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize \fi \thiseurofont } % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% \hfil\crcr\Orb}}% }$% } % Laurent Siebenmann reports \Orb undefined with: % Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 % so we'll define it if necessary. % \ifx\Orb\undefined \def\Orb{\mathhexbox20D} \fi \message{page headings,} \newskip\titlepagetopglue \titlepagetopglue = 1.5in \newskip\titlepagebottomglue \titlepagebottomglue = 2pc % First the title page. Must do @settitle before @titlepage. \newif\ifseenauthor \newif\iffinishedtitlepage % Do an implicit @contents or @shortcontents after @end titlepage if the % user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. % \newif\ifsetcontentsaftertitlepage \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue \newif\ifsetshortcontentsaftertitlepage \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue \parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page \def\page{% \iffinishedtitlepage\else \finishtitlepage \fi \let\page = \oldpage \page \null }% } \def\Etitlepage{% \iffinishedtitlepage\else \finishtitlepage \fi % It is important to do the page break before ending the group, % because the headline and footline are only empty inside the group. % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage \endgroup % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon % % If they want short, they certainly want long too. \ifsetshortcontentsaftertitlepage \shortcontents \contents \global\let\shortcontents = \relax \global\let\contents = \relax \fi % \ifsetcontentsaftertitlepage \contents \global\let\contents = \relax \global\let\shortcontents = \relax \fi } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } %%% Macros to be used within @titlepage: \let\subtitlerm=\tenrm \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines \let\tt=\authortt} \parseargdef\title{% \checkenv\titlepage \leftline{\titlefonts\rm #1} % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\authorfont \leftline{#1}}% \fi } %%% Set up page headings and footings. \let\thispage=\folio \newtoks\evenheadline % headline on even pages \newtoks\oddheadline % headline on odd pages \newtoks\evenfootline % footline on even pages \newtoks\oddfootline % footline on odd pages % Now make TeX use those variables \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}} \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}\HEADINGShook} \let\HEADINGShook=\relax % Commands to set those variables. % For example, this is what @headings on does % @evenheading @thistitle|@thispage|@thischapter % @oddheading @thischapter|@thispage|@thistitle % @evenfooting @thisfile|| % @oddfooting ||@thisfile \def\evenheading{\parsearg\evenheadingxxx} \def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\oddfootingyyy #1\|#2\|#3\|#4\finish{% \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. \global\advance\pageheight by -\baselineskip \global\advance\vsize by -\baselineskip } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @headings double turns headings on for double-sided printing. % @headings single turns headings on for single-sided printing. % @headings off turns them off. % @headings on same as @headings double, retained for compatibility. % @headings after turns on double-sided headings after this page. % @headings doubleafter turns on double-sided headings after this page. % @headings singleafter turns on single-sided headings after this page. % By default, they are off at the start of a document, % and turned `on' after @end titlepage. \def\headings #1 {\csname HEADINGS#1\endcsname} \def\HEADINGSoff{% \global\evenheadline={\hfil} \global\evenfootline={\hfil} \global\oddheadline={\hfil} \global\oddfootline={\hfil}} \HEADINGSoff % When we turn headings on, set the page number to 1. % For double-sided printing, put current file name in lower left corner, % chapter name on inside top of right hand pages, document % title on inside top of left hand pages, and page numbers on outside top % edge of all pages. \def\HEADINGSdouble{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\undefined \def\today{% \number\day\space \ifcase\month \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec \fi \space\number\year} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(x). % default indentation of table text \newdimen\tableindent \tableindent=.8in % default indentation of @itemize and @enumerate text \newdimen\itemindent \itemindent=.3in % margin between end of table item and start of table text. \newdimen\itemmargin \itemmargin=.1in % used internally for \itemindent minus \itemmargin \newdimen\itemmax % Note @table, @ftable, and @vtable define @item, @itemx, etc., with % these defs. % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). \newif\ifitemxneedsnegativevskip \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} \def\internalBitem{\smallbreak \parsearg\itemzzz} \def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#1}}% \itemindex{#1}% \nobreak % This prevents a break before @itemx. % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that % line. We do not start a paragraph here because then if the next % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax % % Make this a paragraph so we get the \parskip glue and wrapping, % but leave it ragged-right. \begingroup \advance\leftskip by-\tableindent \advance\hsize by\tableindent \advance\rightskip by0pt plus1fil \leavevmode\unhbox0\par \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. \nobreak \vskip-\parskip % % Stop a page break at the \parskip glue coming up. However, if % what follows is an environment such as @example, there will be no % \parskip glue; then the negative vskip we just inserted would % cause the example and the item to crash together. So we use this % bizarre value of 10001 as a signal to \aboveenvbreak to insert % \parskip glue after all. Section titles are handled this way also. % \penalty 10001 \endgroup \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. \noindent % Do this with kerns and \unhbox so that if there is a footnote in % the item text, it can migrate to the main vertical list and % eventually be printed. \nobreak\kern-\tableindent \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 \unhbox0 \nobreak\kern\dimen0 \endgroup \itemxneedsnegativevskiptrue \fi } \def\item{\errmessage{@item while not in a list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablecheck{table}% } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablecheck{ftable}% } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablecheck{vtable}% } \def\tablecheck#1{% \ifnum \the\catcode`\^^M=\active \endgroup \errmessage{This command won't work in this context; perhaps the problem is that we are \inenvironment\thisenv}% \def\next{\doignore{#1}}% \else \let\next\tablex \fi \next } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi \def\itemcontents{#1}% % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% \vadjust{\penalty 1200}}% not good to break after first line of item. \flushcr } % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. % \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % If we were given no argument, pretend we were given `1'. \def\thearg{#1}% \ifx\thearg\empty \def\thearg{1}\fi % % Detect if the argument is a single token. If so, it might be a % letter. Otherwise, the only valid thing it can be is a number. % (We will always have one token, because of the test we just made. % This is a good thing, since \splitoff doesn't work given nothing at % all -- the first parameter is undelimited.) \expandafter\splitoff\thearg\endmark \ifx\rest\empty % Only one token in the argument. It could still be anything. % A ``lowercase letter'' is one whose \lccode is nonzero. % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . % \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax \lowercaseenumerate % lowercase letter \else \uppercaseenumerate % uppercase letter \fi \fi \else % Multiple tokens in the argument. We hope it's a number. \numericenumerate \fi } % An @enumerate whose labels are integers. The starting integer is % given in \thearg. % \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% } % The starting (lowercase) letter is in \thearg. \def\lowercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more lowercase letters in @enumerate; get a bigger alphabet}% \fi \char\lccode\itemno }% } % The starting (uppercase) letter is in \thearg. \def\uppercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more uppercase letters in @enumerate; get a bigger alphabet} \fi \char\uccode\itemno }% } % Call \doitemize, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. % \def\startenumeration#1{% \advance\itemno by -1 \doitemize{#1.}\flushcr } % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. % \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} \def\Ecapsenumerate{\Eenumerate} % @multitable macros % Amy Hendrickson, 8/18/94, 3/6/96 % % @multitable ... @end multitable will make as many columns as desired. % Contents of each column will wrap at width given in preamble. Width % can be specified either with sample text given in a template line, % or in percent of \hsize, the current width of text on page. % Table can continue over pages but will only break between lines. % To make preamble: % % Either define widths of columns in terms of percent of \hsize: % @multitable @columnfractions .25 .3 .45 % @item ... % % Numbers following @columnfractions are the percent of the total % current hsize to be used for each column. You may use as many % columns as desired. % Or use a template: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item ... % using the widest term desired in each column. % Each new table line starts with @item, each subsequent new column % starts with @tab. Empty columns may be produced by supplying @tab's % with nothing between them for as many times as empty columns are needed, % ie, @tab@tab@tab will produce two empty columns. % @item, @tab do not need to be on their own lines, but it will not hurt % if they are. % Sample multitable: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item first col stuff @tab second col stuff @tab third col % @item % first col stuff % @tab % second col stuff % @tab % third col % @item first col stuff @tab second col stuff % @tab Many paragraphs of text may be used in any column. % % They will wrap at the width determined by the template. % @item@tab@tab This will be in third column. % @end multitable % Default dimensions may be reset by user. % @multitableparskip is vertical space between paragraphs in table. % @multitableparindent is paragraph indent in table. % @multitablecolmargin is horizontal space to be left between columns. % @multitablelinespace is space to leave between table items, baseline % to baseline. % 0pt means it depends on current normal line spacing. % \newskip\multitableparskip \newskip\multitableparindent \newdimen\multitablecolspace \newskip\multitablelinespace \multitableparskip=0pt \multitableparindent=6pt \multitablecolspace=12pt \multitablelinespace=0pt % Macros used to set up halign preamble: % \let\endsetuptable\relax \def\xendsetuptable{\endsetuptable} \let\columnfractions\relax \def\xcolumnfractions{\columnfractions} \newif\ifsetpercent % #1 is the @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% \setuptable } \newcount\colcount \def\setuptable#1{% \def\firstarg{#1}% \ifx\firstarg\xendsetuptable \let\go = \relax \else \ifx\firstarg\xcolumnfractions \global\setpercenttrue \else \ifsetpercent \let\go\pickupwholefraction \else \global\advance\colcount by 1 \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a % separator; typically that is always in the input, anyway. \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% \fi \fi \ifx\go\pickupwholefraction % Put the argument back for the \pickupwholefraction call, so % we'll always have a period there to be parsed. \def\go{\pickupwholefraction#1}% \else \let\go = \setuptable \fi% \fi \go } % multitable-only commands. % % @headitem starts a heading row, which we typeset in bold. % Assignments have to be global since we are inside the implicit group % of an alignment entry. Note that \everycr resets \everytab. \def\headitem{\checkenv\multitable \crcr \global\everytab={\bf}\the\everytab}% % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we encounter the problem it was intended to solve again. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. % We use \def instead of \let so that if one of the multitable entries % contains an @itemize, we don't choke on the \item (seen as \crcr aka % \endtemplate) expanding \doitemize. \def\item{\crcr}% % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% \global\colcount=0 % Reset the column counter. % Check for saved footnotes, etc. \checkinserts % Keeps underfull box messages off when table breaks over pages. %\filbreak % Maybe so, but it also creates really weird page breaks when the % table breaks over pages. Wouldn't \vfil be better? Wait until the % problem manifests itself, so it can be fixed for real --karl. }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % This preamble sets up a generic column definition, which will % be used as many times as user calls for columns. % \vtop will set a single line and will also let text wrap and % continue for many paragraphs if desired. \halign\bgroup &% \global\advance\colcount by 1 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \hsize=\expandafter\csname col\the\colcount\endcsname % % In order to keep entries from bumping into each other % we will add a \leftskip of \multitablecolspace to all columns after % the first one. % % If a template has been used, we will add \multitablecolspace % to the width of each template entry. % % If the user has set preamble in terms of percent of \hsize we will % use that dimension as the width of the column, and the \leftskip % will keep entries from bumping into each other. Table will start at % left margin and final column will justify at right margin. % % Make sure we don't inherit \rightskip from the outer environment. \rightskip=0pt \ifnum\colcount=1 % The first column will be indented with the surrounding text. \advance\hsize by\leftskip \else \ifsetpercent \else % If user has not set preamble in terms of percent of \hsize % we will advance \hsize by \multitablecolspace. \advance\hsize by \multitablecolspace \fi % In either case we will make \leftskip=\multitablecolspace: \leftskip=\multitablecolspace \fi % Ignoring space at the beginning and end avoids an occasional spurious % blank line, when TeX decides to break the line at the space before the % box from the multistrut, so the strut ends up on a line by itself. % For example: % @multitable @columnfractions .11 .89 % @item @code{#} % @tab Legal holiday which is valid in major parts of the whole country. % Is automatically provided with highlighting sequences respectively % marking characters. \noindent\ignorespaces##\unskip\multistrut }\cr } \def\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% \def\multistrut{\strut}% just use the standard line spacing % % Compute \multitablelinespace (if not defined by user) for use in % \multitableparskip calculation. We used define \multistrut based on % this, but (ironically) that caused the spacing to be off. % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 \fi %% Test to see if parskip is larger than space between lines of %% table. If not, do nothing. %% If so, set to same dimension as multitablelinespace. \ifdim\multitableparskip>\multitablelinespace \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi% \ifdim\multitableparskip=0pt \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi} \message{conditionals,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \obeylines \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore{#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the command name as a string, e.g., `ifinfo'. % % Define a command to find the next `@end #1'. \long\def\doignoretext##1^^M@end #1{% \doignoretextyyy##1^^M@#1\_STOP_}% % % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. { \obeylines% % Ignore anything after the last `@end #1'; this matters in verbatim % environments, where otherwise the newline after an ignored conditional % would result in a blank line in the output. \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% } % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. % % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we % didn't need it. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\- = \active \catcode`\_ = \active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\realdash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), since % the result winds up in the index file. This means that if the % variable's value contains other Texinfo commands, it's almost certain % it will fail (although perhaps we could fix that with sufficient work % to do a one-level expansion on the result, instead of complete). % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get special treatment of `@end ifset,' call \makeond and the redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @defininfoenclose. \let\definfoenclose=\comment \message{indexing,} % Index generation facilities % Define \newwrite to be identical to plain tex's \newwrite % except not \outer, so it can be used within macros and \if's. \edef\newwrite{\makecsname{ptexnewwrite}} % \newindex {foo} defines an index named foo. % It automatically defines \fooindex such that % \fooindex ...rest of line... puts an entry in the index foo. % It also defines \fooindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is foo. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 % Open the file \fi \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 \fi \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % @synindex foo bar makes index foo feed into index bar. % Do this instead of @defindex foo if you don't want it as a separate index. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% % Only do \closeout if we haven't already done it, else we'll end up % closing the target index. \expandafter \ifx\csname donesynindex#2\endcsname \undefined % The \closeout helps reduce unnecessary open files; the limit on the % Acorn RISC OS is a mere 16 files. \expandafter\closeout\csname#2indfile\endcsname \expandafter\let\csname\donesynindex#2\endcsname = 1 \fi % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all \fooindex macros. % Argument #1 is generated by the calling \fooindex macro, % and it is "foo", the name of the index. % \doindex just uses \parsearg; it calls \doind for the actual work. % This is because \doind is more useful to call from other macros. % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} \def\singleindexer #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} % Take care of Texinfo commands that can appear in an index entry. % Since there are some commands we want to expand, and others we don't, % we have to laboriously prevent expansion for those that we don't. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. \def\@{@}% change to @@ when we switch to @ as escape char in index files. \def\ {\realbackslash\space }% % Need these in case \tex is in effect and \{ is a \delimiter again. % But can't use \lbracecmd and \rbracecmd because texindex assumes % braces and backslashes are used only as delimiters. \let\{ = \mylbrace \let\} = \myrbrace % % Do the redefinitions. \commondummies } % For the aux and toc files, @ is the escape character. So we want to % redefine everything using @ as the escape character (instead of % \realbackslash, still used for index files). When everything uses @, % this will be simpler. % \def\atdummies{% \def\@{@@}% \def\ {@ }% \let\{ = \lbraceatcmd \let\} = \rbraceatcmd % % Do the redefinitions. \commondummies \otherbackslash } % Called from \indexdummies and \atdummies. % \def\commondummies{% % % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control% words, % not control letters, because the \space would be incorrect for % control characters, but is needed to separate the control word % from whatever follows. % % For control letters, we have \definedummyletter, which omits the % space. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % \def\definedummyword ##1{\def##1{\string##1\space}}% \def\definedummyletter##1{\def##1{\string##1}}% \let\definedummyaccent\definedummyletter % \commondummiesnofonts % \definedummyletter\_% % % Non-English letters. \definedummyword\AA \definedummyword\AE \definedummyword\L \definedummyword\OE \definedummyword\O \definedummyword\aa \definedummyword\ae \definedummyword\l \definedummyword\oe \definedummyword\o \definedummyword\ss \definedummyword\exclamdown \definedummyword\questiondown \definedummyword\ordf \definedummyword\ordm % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword\bf \definedummyword\gtr \definedummyword\hat \definedummyword\less \definedummyword\sf \definedummyword\sl \definedummyword\tclose \definedummyword\tt % \definedummyword\LaTeX \definedummyword\TeX % % Assorted special characters. \definedummyword\bullet \definedummyword\comma \definedummyword\copyright \definedummyword\registeredsymbol \definedummyword\dots \definedummyword\enddots \definedummyword\equiv \definedummyword\error \definedummyword\euro \definedummyword\expansion \definedummyword\minus \definedummyword\pounds \definedummyword\point \definedummyword\print \definedummyword\result % % We want to disable all macros so that they are not expanded by \write. \macrolist % \normalturnoffactive % % Handle some cases of @value -- where it does not contain any % (non-fully-expandable) commands. \makevalueexpandable } % \commondummiesnofonts: common to \commondummies and \indexnofonts. % \def\commondummiesnofonts{% % Control letters and accents. \definedummyletter\!% \definedummyaccent\"% \definedummyaccent\'% \definedummyletter\*% \definedummyaccent\,% \definedummyletter\.% \definedummyletter\/% \definedummyletter\:% \definedummyaccent\=% \definedummyletter\?% \definedummyaccent\^% \definedummyaccent\`% \definedummyaccent\~% \definedummyword\u \definedummyword\v \definedummyword\H \definedummyword\dotaccent \definedummyword\ringaccent \definedummyword\tieaccent \definedummyword\ubaraccent \definedummyword\udotaccent \definedummyword\dotless % % Texinfo font commands. \definedummyword\b \definedummyword\i \definedummyword\r \definedummyword\sc \definedummyword\t % % Commands that take arguments. \definedummyword\acronym \definedummyword\cite \definedummyword\code \definedummyword\command \definedummyword\dfn \definedummyword\emph \definedummyword\env \definedummyword\file \definedummyword\kbd \definedummyword\key \definedummyword\math \definedummyword\option \definedummyword\pxref \definedummyword\ref \definedummyword\samp \definedummyword\strong \definedummyword\tie \definedummyword\uref \definedummyword\url \definedummyword\var \definedummyword\verb \definedummyword\w \definedummyword\xref } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% % Accent commands should become @asis. \def\definedummyaccent##1{\let##1\asis}% % We can just ignore other control letters. \def\definedummyletter##1{\let##1\empty}% % Hopefully, all control words can become @asis. \let\definedummyword\definedummyaccent % \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% % how to handle braces? \def\_{\normalunderscore}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\aa{aa}% \def\ae{ae}% \def\l{l}% \def\oe{oe}% \def\o{o}% \def\ss{ss}% \def\exclamdown{!}% \def\questiondown{?}% \def\ordf{a}% \def\ordm{o}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. % (The following {} will end up in the sort string, but that's ok.) \def\bullet{bullet}% \def\comma{,}% \def\copyright{copyright}% \def\registeredsymbol{R}% \def\dots{...}% \def\enddots{...}% \def\equiv{==}% \def\error{error}% \def\euro{euro}% \def\expansion{==>}% \def\minus{-}% \def\pounds{pounds}% \def\point{.}% \def\print{-|}% \def\result{=>}% % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. % makeinfo does not expand macros in the argument to @deffn, which ends up % writing an index entry, and texindex isn't prepared for an index sort entry % that starts with \. % % Since macro invocations are followed by braces, we can just redefine them % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % \macrolist } \let\indexbackslash=0 %overridden during \printindex. \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % Workhorse for all \fooindexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \ifvmode \dosubindsanitize \else \dosubindwrite \fi }% \fi } % Write the entry in \toks0 to the index file: % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now % so it will be output as is; and it will print as backslash. % % Process the index entry with all font commands turned off, to % get the string to sort by. {\indexnofonts \edef\temp{\the\toks0}% need full expansion \xdef\indexsorttmp{\temp}% }% % % Set up the complete index entry, with both the sort key and % the original text, including any font commands. We write % three arguments to \entry to the .?? file (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% }% \temp } % Take care of unwanted page breaks: % % If a skip is the last thing on the list now, preserve it % by backing up by \lastskip, doing the \write, then inserting % the skip again. Otherwise, the whatsit generated by the % \write will make \lastskip zero. The result is that sequences % like this: % @end defun % @tindex whatever % @defun ... % will have extra space inserted, because the \medbreak in the % start of the @defun won't see the skip inserted by the @end of % the previous defun. % % But don't do any of this if we're not in vertical mode. We % don't want to do a \vskip and prematurely end a paragraph. % % Avoid page breaks due to these extra skips, too. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % % ..., ready, GO: % \def\dosubindsanitize{% % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \skip0 = \lastskip \edef\lastskipmacro{\the\lastskip}% \count255 = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\skip0 glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\skip0 \fi % \dosubindwrite % \ifx\lastskipmacro\zeroskipmacro % If \lastskip was zero, perhaps the last item was a penalty, and % perhaps it was >=10000, e.g., a \nobreak. In that case, we want % to re-insert the same penalty (values >10000 are used for various % signals); since we just inserted a non-discardable item, any % following glue (such as a \parskip) would be a breakpoint. For example: % % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\count255>9999 \penalty\count255 \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\skip0 \fi } % The index entry written in the file actually looks like % \entry {sortstring}{page}{topic} % or % \entry {sortstring}{page}{topic}{subtopic} % The texindex program reads in these files and writes files % containing these kinds of lines: % \initial {c} % before the first topic whose initial is c % \entry {topic}{pagelist} % for a topic that is used without subtopics % \primary {topic} % for the beginning of a topic that is used with subtopics % \secondary {subtopic}{pagelist} % for each subtopic. % Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} \def\kindex {\kyindex} \def\cindex {\cpindex} \def\vindex {\vrindex} \def\tindex {\tpindex} \def\pindex {\pgindex} \def\cindexsub {\begingroup\obeylines\cindexsub} {\obeylines % \gdef\cindexsub "#1" #2^^M{\endgroup % \dosubind{cp}{#2}{#1}}} % Define the macros used in formatting output of the sorted index material. % @printindex causes a particular index (the ??s file) to get printed. % It does not print any chapter heading (usually an @unnumbered). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % See if the index file exists and is nonempty. % Change catcode of @ here so that if the index file contains % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). \catcode`\@ = 11 \openin 1 \jobname.#1s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \else % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \temp \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\backslashcurfont}% \catcode`\\ = 0 \escapechar = `\\ \begindoublecolumns \input \jobname.#1s \enddoublecolumns \fi \fi \closein 1 \endgroup} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. \def\initial#1{{% % Some minor font changes for the special characters. \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt % % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. \nobreak \vskip 0pt plus 3\baselineskip \penalty 0 \vskip 0pt plus -3\baselineskip % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column % to column. It still won't often be perfect, because of the stretch % we need before each entry, but it's better. % % No shrink because it confuses \balancecolumns. \vskip 1.67\baselineskip plus .5\baselineskip \leftline{\secbf #1}% % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip }} % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % % A straightforward implementation would start like this: % \def\entry#1#2{... % But this frozes the catcodes in the argument, and can cause problems to % @code, which sets - active. This problem was fixed by a kludge--- % ``-'' was active throughout whole index, but this isn't really right. % % The right solution is to prevent \entry from swallowing the whole text. % --kasal, 21nov03 \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % Do not fill out the last line with white space. \parfillskip = 0in % % No extra space above this paragraph. \parskip = 0in % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % \hangindent is only relevant when the entry text and page number % don't both fit on one line. In that case, bob suggests starting the % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent = 2em % % When the entry text needs to be broken, just fill out the first line % with blank space. \rightskip = 0pt plus1fil % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus1pt % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\doentry{% \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. } \def\finishentry#1{% % #1 is the page number. % % The following is kludged to not output a line of dots in the index if % there are no page numbers. The next person who breaks this will be % cursed by a Unix daemon. \def\tempa{{\rm }}% \def\tempb{#1}% \edef\tempc{\tempa}% \edef\tempd{\tempb}% \ifx\tempc\tempd \ % \else % % If we must, put the page number on a line of its own, and fill out % this line with blank space. (The \hfil is overwhelmed with the % fill leaders glue in \indexdotfill if the page number does fit.) \hfil\penalty50 \null\nobreak\indexdotfill % Have leaders before the page number. % % The `\ ' here is removed by the implicit \unskip that TeX does as % part of (the primitive) \par. Without it, a spurious underfull % \hbox ensues. \ifpdf \pdfgettoks#1.% \ \the\toksA \else \ #1% \fi \fi \par \endgroup } % Like \dotfill except takes at least 1 em. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else #2 \fi \par }} % Define two-column mode, which we use to typeset indexes. % Adapted from the TeXbook, page 416, which is to say, % the manmac.tex format used to print the TeXbook itself. \catcode`\@=11 \newbox\partialpage \newdimen\doublecolumnhsize \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% }% \eject % run that output routine to set \partialpage % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. (We don't need a separate register here, % since nobody clobbers \vsize.) \vsize = 2\vsize } % The double-column output routine for all double-column pages except % the last. % \def\doublecolumnout{% \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% } % % All done with double columns. \def\enddoublecolumns{% \output = {% % Split the last of the double-column material. Leave it on the % current page, no automatic page break. \balancecolumns % % If we end up splitting too much material for the current page, % though, there will be another page break right after this \output % invocation ends. Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. (We hope \balancecolumns will never be % called on to balance too much material, but if it is, this makes % the output somewhat more palatable.) \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize (after the % \endgroup where \vsize got restored). \pagegoal = \vsize } % % Called at the end of the double column material. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \divide\dimen@ by 2 % target to split to %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% \splittopskip = \topskip % Loop until we get a decent breakpoint. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht3>\dimen@ \global\advance\dimen@ by 1pt \repeat }% %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% % \pagesofar } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % \unnumberedno is an oxymoron, of course. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \newcount\chapno \newcount\secno \secno=0 \newcount\subsecno \subsecno=0 \newcount\subsubsecno \subsubsecno=0 % This counter is funny since it counts through charcodes of letters A, B, ... \newcount\appendixno \appendixno = `\@ % % \def\appendixletter{\char\the\appendixno} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines this as the name of the chapter. % page headings and footings can use it. @section does likewise. % However, they are not reliable, because we don't use marks. \def\thischapter{} \def\thissection{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count % @raisesections: treat @section as chapter, @subsection as section, etc. \def\raisesections{\global\advance\secbase by -1} \let\up=\raisesections % original BFox name % @lowersections: treat @chapter as section, @section as subsection, etc. \def\lowersections{\global\advance\secbase by 1} \let\down=\lowersections % original BFox name % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achive this, remember the "biggest" unnum. sec. we are currently in: \chardef\unmlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unmlevel \chardef\unmlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unmlevel \def\headtype{U}% \else \chardef\unmlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % \message{\putwordChapter\space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally apphead0 calls appendixzzz \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % \def\appendixnum{\putwordAppendix\space \appendixletter}% \message{\appendixnum}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } \outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % This used to be simply \message{#1}, but TeX fully expands the % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant % to be executed, not expanded). % % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, % simply yielding the contents of . (We also do this for % the toc entries.) \toks0 = {#1}% \message{(\the\toks0)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% % Well, we could do the following in a group, but that would break % an assumption that \chapmacro is called at the outermost level. % Thus we are safer this way: --kasal, 24feb04 \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } \outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. \outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } \outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % These macros control what the section commands do, according % to what kind of chapter we are in (ordinary, appendix, or unnumbered). % Define them by default for a numbered chapter. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading % NOTE on use of \vbox for chapter headings, section headings, and such: % 1) We use \vbox rather than the earlier \line to permit % overlong headings to fold. % 2) \hyphenpenalty is set to 10000 because hyphenation in a % heading is obnoxious; this forbids it. % 3) Likewise, headings look best if no \parindent is used, and % if justification is not attempted. Hence \raggedright. \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\raggedright \rm #1\hfill}}% \bigskip \par\penalty 200\relax \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % These macros generate a chapter, section, etc. heading only % (including whitespace, linebreaking, etc. around it), % given all the information in convenient, parsed form. %%% Args are the skip and penalty (usually negative) \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} %%% Define plain chapter starts, and page on/off switching for it % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip \def\chapbreak{\dobreak \chapheadingskip {-4000}} \def\chappager{\par\vfill\supereject} \def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} \def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chapbreak \global\let\pagealignmacro=\chappager} \def\CHAPPAGon{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chappager \global\let\pagealignmacro=\chappager \global\def\HEADINGSon{\HEADINGSsingle}} \def\CHAPPAGodd{% \global\let\contentsalignmacro = \chapoddpage \global\let\pchapsepmacro=\chapoddpage \global\let\pagealignmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} \CHAPPAGon % Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yomitfromtockeyword{Yomitfromtoc} \def\Yappendixkeyword{Yappendix} % \def\chapmacro#1#2#3{% \pchapsepmacro {% \chapfonts \rm % % Have to define \thissection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\thissection{#1}% \gdef\thischaptername{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \gdef\thischapter{#1}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \gdef\thischapter{}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% % We don't substitute the actual chapter name into \thischapter % because we don't want its macros evaluated now. And we don't % use \thissection because that changes with each section. % \xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % I don't think this chapter style is supported any more, so I'm not % updating it with the new noderef stuff. We'll see. --karl, 11aug03. % \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} % \def\unnchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\raggedright \rm #1\hfill}}\bigskip \par\nobreak } \def\chfopen #1#2{\chapoddpage {\chapfonts \vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% \par\penalty 5000 % } \def\centerchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt \hfill {\rm #1}\hfill}}\bigskip \par\nobreak } \def\CHAPFopen{% \global\let\chapmacro=\chfopen \global\let\centerchapmacro=\centerchfopen} % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is % the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the % section number. % \def\sectionheading#1#2#3#4{% {% % Switch to the right set of fonts. \csname #2fonts\endcsname \rm % % Insert space above the heading. \csname #2headingbreak\endcsname % % Only insert the space after the number if we have a section number. \def\sectionlevel{#2}% \def\temptype{#3}% % \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\thissection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \thissection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\thissection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\thissection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chapmacro. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chapmacro. \donoderef{#3}% % % Interline glue will be inserted when the vbox is completed. % That glue will be a valid breakpoint for the page, since it'll be % preceded by a whatsit (usually from the \donoderef, or from the % \writetocentry if there was no node). We don't want to allow that % break, since then the whatsits could end up on page n while the % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. \nobreak % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) \vskip-\parskip % % This is purely so the last item on the list is a known \penalty > % 10000. This is so \startdefun can avoid allowing breakpoints after % section headings. Otherwise, it would insert a valid breakpoint between: % % @section sec-whatever % @deffn def-whatever \penalty 10001 } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks {\atdummies \edef\temp{% \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% \temp }% \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \fi } % These characters do not print properly in the Computer Modern roman % fonts, so we must take special care. This is more or less redundant % with the Texinfo input format setup at the end of this file. % \def\activecatcodes{% \catcode`\"=\active \catcode`\$=\active \catcode`\<=\active \catcode`\>=\active \catcode`\\=\active \catcode`\^=\active \catcode`\_=\active \catcode`\|=\active \catcode`\~=\active } % Read the toc file, which is essentially Texinfo input. \def\readtocfile{% \setupdatafile \activecatcodes \input \jobname.toc } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % Prepare to read what we've written to \tocfile. % \def\startcontents#1{% % If @setchapternewpage on, and @headings double, the contents should % start on an odd page, unlike chapters. Thus, we maintain % \contentsalignmacro in parallel with \pagealignmacro. % From: Torbjorn Granlund \contentsalignmacro \immediate\closeout\tocfile % % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \def\thischapter{}% \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % Normal (long) toc. \def\contents{% \startcontents{\putwordTOC}% \openin 1 \jobname.toc \ifeof 1 \else \readtocfile \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \jobname.toc \ifeof 1 \else \readtocfile \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % These macros generate individual entries in the table of contents. % The first argument is the chapter or section name. % The last argument is the page number. % The arguments in between are the chapter number, section number, ... % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % % If the toc has to be broken over pages, we want it to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip \begingroup \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} \def\dopageno#1{{\rm #1}} \def\doshortpageno#1{{\rm #1}} \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, it should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\tentt \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} % \setbox\errorbox=\hbox to \dimen0{\hfil \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. \advance\hsize by -2\dimen2 % Rules. \vbox{% \hrule height\dimen2 \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. \kern3pt\vrule width\dimen2}% Space to right. \hrule height\dimen2} \hfil} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @tex ... @end tex escapes into raw Tex temporarily. % One exception: @ is still an escape character, so that @end tex works. % But \@ or @@ will get a plain tex @ character. \envdef\tex{% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \escapechar=`\\ % \let\b=\ptexb \let\bullet=\ptexbullet \let\c=\ptexc \let\,=\ptexcomma \let\.=\ptexdot \let\dots=\ptexdots \let\equiv=\ptexequiv \let\!=\ptexexclam \let\i=\ptexi \let\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\*=\ptexstar \let\t=\ptext \let\frenchspacing=\plainfrenchspacing % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (which normally is erroneous). % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in % This is the definition that ^^M gets inside @lisp, @example, and other % such environments. \null is better than a space, since it doesn't % have any width. \def\lisppar{\null\endgraf} % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt % Make spacing and below environment symmetrical. We use \parskip here % to help in doing that, since in @example-like environments \parskip % is reset to zero; thus the \afterenvbreak inserts no space -- but the % start of the next paragraph will insert \parskip. % \def\aboveenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} \let\afterenvbreak = \aboveenvbreak % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will % also clear it, so that its embedded environments do the narrowing again. \let\nonarrowing=\relax % @cartouche ... @end cartouche: draw rectangle w/rounded corners around % environment contents. \font\circle=lcircle10 \newdimen\circthick \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip \circthick=\fontdimen8\circle % \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth \def\ctr{{\hskip 6pt\circle\char'010}} \def\cbl{{\circle\char'012\hskip -6pt}} \def\cbr{{\hskip 6pt\circle\char'011}} \def\carttop{\hbox to \cartouter{\hskip\lskip \ctl\leaders\hrule height\circthick\hfil\ctr \hskip\rskip}} \def\cartbot{\hbox to \cartouter{\hskip\lskip \cbl\leaders\hrule height\circthick\hfil\cbr \hskip\rskip}} % \newskip\lskip\newskip\rskip \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt % we want these *outside*. \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18.4pt % allow for 3pt kerns on either % side, and for 6pt waste from % each corner char, and rule thickness \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip % Flag to tell @lisp, etc., not to narrow margin. \let\nonarrowing = t% \vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of \def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \def\nonfillstart{% \aboveenvbreak \hfuzz = 12pt % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt \parindent = 0pt \emergencystretch = 0pt % don't try to avoid overfull boxes \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \else \let\nonarrowing = \relax \fi \let\exdent=\nofillexdent } % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it by one command: \def\makedispenv #1#2{ \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two synonyms: \def\maketwodispenvs #1#2#3{ \makedispenv{#1}{#3} \makedispenv{#2}{#3} } % @lisp: indented, narrowed, typewriter font; @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvs {lisp}{example}{% \nonfillstart \tt \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenv {display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenv{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill \gobble } \let\Eflushright = \afterenvbreak % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \envdef\quotation{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \advance\rightskip by \lispnarrowing \exdentamount = \lispnarrowing \else \let\nonarrowing = \relax \fi \parsearg\quotationlabel } % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\undefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % [Knuth] pp. 380,381,391 % Disable Spanish ligatures ?` and !` of \tt font \begingroup \catcode`\`=\active\gdef`{\relax\lq} \endgroup % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \catcode`\`=\active \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % \def\starttabbox{\setbox0=\hbox\bgroup} \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen0=\wd0 % the width so far, or since the previous tab \divide\dimen0 by\tabw \multiply\dimen0 by\tabw % compute previous multiple of \tabw \advance\dimen0 by\tabw % advance to next multiple of \tabw \wd0=\dimen0 \box0 \starttabbox }% } \endgroup \def\setupverbatim{% \let\nonarrowing = t% \nonfillstart % Easiest (and conventionally used) font for verbatim \tt \def\par{\leavevmode\egroup\box0\endgraf}% \catcode`\`=\active \tabexpand % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is very desirable. % \def\copying{\checkenv{}\begingroup\scanargctxt\docopying} \def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} % \def\insertcopying{% \begingroup \parindent = 0pt % paragraph indentation looks wrong on title page \scanexp\copyingtext \endgroup } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check specifically for penalty 10002, inserted % by \defargscommonending, instead of 10000, since the sectioning % commands also insert a nobreak penalty, and we don't want to allow % a break between a section heading and a defun. % \ifnum\lastpenalty=10002 \penalty2000 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil \endgraf \nobreak\vskip -\parskip \penalty 10002 % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remainnig is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } %%% Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } %%% Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } %%% Type: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % How we'll format the type name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % (plain.tex says that \dimen1 should be used only as global.) \parshape 2 0in \dimen0 \defargsindent \dimen2 % % Put the type name to the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% return value type \ifx\temp\empty\else \tclose{\temp} \fi #3% output function name }% {\rm\enskip}% hskip 0.5 em of \tenrm % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. Let's try @var for that. \let\var=\ttslanted #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \def\activeparens{% \catcode`\(=\active \catcode`\)=\active \catcode`\[=\active \catcode`\]=\active \catcode`\&=\active } % Make control sequences which act like normal parenthesis chars. \let\lparen = ( \let\rparen = ) % Be sure that we always have a definition for `(', etc. For example, % if the fn name has parens in it, \boldbrax will not be in effect yet, % so TeX would otherwise complain about undefined control sequence. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } \def\badparencount{% \errmessage{Unbalanced parentheses in @def}% \global\parencount=0 } \def\badbrackcount{% \errmessage{Unbalanced square braces in @def}% \global\brackcount=0 } \message{macros,} % @macro. % To do this right we need a feature of e-TeX, \scantokens, % which we arrange to emulate with a temporary file in ordinary TeX. \ifx\eTeXversion\undefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi \def\scanmacro#1{% \begingroup \newlinechar`\^^M \let\xeatspaces\eatspaces % Undo catcode changes of \startcontents and \doprintindex % When called from @insertcopying or (short)caption, we need active % backslash to get it printed correctly. Previously, we had % \catcode`\\=\other instead. We'll see whether a problem appears % with macro expansion. --kasal, 19aug04 \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ % ... and \example \spaceisspace % % Append \endinput to make sure that TeX does not see the ending newline. % % I've verified that it is necessary both for e-TeX and for ordinary TeX % --kasal, 29nov03 \scantokens{#1\endinput}% \endgroup } \def\scanexp#1{% \edef\temp{\noexpand\scanmacro{#1}}% \temp } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? % List of all defined macros in the form % \definedummyword\macro1\definedummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% \toks0 = \expandafter{\macrolist\definedummyword#1}% \xdef\macrolist{\the\toks0}% } % Utility routines. % This does \let #1 = #2, with \csnames; that is, % \let \csname#1\endcsname = \csname#2\endcsname % (except of course we have to play expansion games). % \def\cslet#1#2{% \expandafter\let \csname#1\expandafter\endcsname \csname#2\endcsname } % Trim leading and trailing spaces off a string. % Concepts from aro-bend problem 15 (see CTAN). {\catcode`\@=11 \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} \def\unbrace#1{#1} \unbrace{\gdef\trim@@@ #1 } #2@{#1} } % Trim a single trailing ^^M off a string. {\catcode`\^^M=\other \catcode`\Q=3% \gdef\eatcr #1{\eatcra #1Q^^MQ}% \gdef\eatcra#1^^MQ{\eatcrb#1Q}% \gdef\eatcrb#1Q#2Q{#1}% } % Macro bodies are absorbed as an argument in a context where % all characters are catcode 10, 11 or 12, except \ which is active % (as in normal texinfo). It is necessary to change the definition of \. % It's necessary to have hard CRs when the macro is executed. This is % done by making ^^M (\endlinechar) catcode 12 when reading the macro % body, and then making it the \newlinechar in \scanmacro. \def\scanctxt{% \catcode`\"=\other \catcode`\+=\other \catcode`\<=\other \catcode`\>=\other \catcode`\@=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other } \def\scanargctxt{% \scanctxt \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% \scanctxt \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } \def\macroargctxt{% \scanctxt \catcode`\\=\other } % \mbodybackslash is the definition of \ in @macro bodies. % It maps \foo\ => \csname macarg.foo\endcsname => #N % where N is the macro parameter number. % We define \csname macarg.\endcsname to be \realbackslash, so % \\ in macro replacement text gets you a backslash. {\catcode`@=0 @catcode`@\=@active @gdef@usembodybackslash{@let\=@mbodybackslash} @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} } \expandafter\def\csname macarg.\endcsname{\realbackslash} \def\macro{\recursivefalse\parsearg\macroxxx} \def\rmacro{\recursivetrue\parsearg\macroxxx} \def\macroxxx#1{% \getargs{#1}% now \macname is the macname and \argl the arglist \ifx\argl\empty % no arguments \paramno=0% \else \expandafter\parsemargdef \argl;% \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% \addtomacrolist{\the\macname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \if1\csname ismacro.#1\endcsname \global\cslet{#1}{macsave.#1}% \global\expandafter\let \csname ismacro.#1\endcsname=0% % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax \let\definedummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx #1\relax % remove this \else \noexpand\definedummyword \noexpand#1% \fi } % This makes use of the obscure feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname #1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % Parse the optional {params} list. Set up \paramno and \paramlist % so \defmacro knows what to do. Define \macarg.blah for each blah % in the params list, to be ##N where N is the position in that list. % That gets used by \mbodybackslash (above). % We need to get `macro parameter char #' into several definitions. % The technique used is stolen from LaTeX: let \hash be something % unexpandable, insert that wherever you need a #, and then redefine % it to # just before using the token list produced. % % The same technique is used to protect \eatspaces till just before % the macro is used. \def\parsemargdef#1;{\paramno=0\def\paramlist{}% \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1% \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} % These two commands read recursive and nonrecursive macro bodies. % (They're different since rec and nonrec macros end differently.) \long\def\parsemacbody#1@end macro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \long\def\parsermacbody#1@end rmacro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% % This defines the macro itself. There are six cases: recursive and % nonrecursive macros of zero, one, and many arguments. % Much magic with \expandafter here. % \xdef is used so that macro definitions will survive the file % they're defined in; @include reads the file inside a group. \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifrecursive \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\temp}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup\noexpand\scanmacro{\temp}}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{\egroup\noexpand\scanmacro{\temp}}% \fi \else \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \expandafter\noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \fi \fi} \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} % \braceorline decides whether the next nonwhitespace character is a % {. If so it reads up to the closing }, if not, it reads the whole % line. Whatever was read is then fed to the next control sequence % as an argument (by \parsebrace or \parsearg) \def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup\else \expandafter\parsearg \fi \next} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Just make them active and then expand them all to nothing. \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \addtomacrolist{#1}% \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \message{cross references,} \newwrite\auxfile \newif\ifhavexrefs % True if xref values are known. \newif\ifwarnedxrefs % True if we warned once that they aren't known. % @inforef is relatively simple. \def\inforef #1{\inforefzzz #1,,,,**} \def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} % @node's only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \thissection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \atdummies % preserve commands, but don't expand them \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\thissection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \writexrdef{pg}{\folio}% will be written later, during \shipout }% \fi } % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is % the node name, #2 the name of the Info cross-reference, #3 the printed % node name, #4 the name of the Info file, #5 the name of the printed % manual. All but the node name can be omitted. % \def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces \def\printedmanual{\ignorespaces #5}% \def\printedrefname{\ignorespaces #3}% \setbox1=\hbox{\printedmanual\unskip}% \setbox0=\hbox{\printedrefname\unskip}% \ifdim \wd0 = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax % Use the node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Use the actual chapter/section title appear inside % the square brackets. Use the real section title if we have it. \ifdim \wd1 > 0pt % It is in another manual, so we don't have it. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf \leavevmode \getfilename{#4}% {\turnoffactive % See comments at \activebackslashdouble. {\activebackslashdouble \xdef\pdfxrefdest{#1}% \backslashparens\pdfxrefdest}% % \ifnum\filenamelength>0 \startlink attr{/Border [0 0 0]}% goto file{\the\filename.pdf} name{\pdfxrefdest}% \else \startlink attr{/Border [0 0 0]}% goto name{\pdfmkpgn{\pdfxrefdest}}% \fi }% \linkcolor \fi % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". We distinguish them by the % LABEL-title being set to a magic string. {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd0 = 0pt \refx{#1-snt}{}% \else \printedrefname \fi % % if the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd1 > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not % insert empty discretionaries after hyphens, which means that it will % not find a line break at a hyphen in a node names. Since some manuals % are best written with fairly long node names, containing hyphens, this % is a loss. Therefore, we give the text of the node name again, so it % is as if TeX is seeing it for the first time. \ifdim \wd1 > 0pt \putwordsection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% \else % _ (for example) has to be the character _ for the purposes of the % control sequence corresponding to the node, but it has to expand % into the usual \leavevmode...\vrule stuff for purposes of % printing. So we \turnoffactive for the \refx-snt, back on for the % printing, back off for the \refx-pg. {\turnoffactive % Only output a following space if the -snt ref is nonempty; for % @unnumbered and @anchor, it won't be. \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi }% % output the `[mynode]' via a macro so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \putwordpage\tie\refx{#1-pg}{}% \fi \fi \endlink \endgroup} % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } % Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. % If its value is nonempty, SUFFIX is output afterward. % \def\refx#1#2{% {% \indexnofonts \otherbackslash \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs \message{\linenumber Undefined cross reference `#1'.}% \else \ifwarnedxrefs\else \global\warnedxrefstrue \message{Cross reference values unknown; you must run TeX again.}% \fi \fi \fi \else % It's defined, so just use it. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Usually it's % just a \def (we prepend XR to the control sequence name to avoid % collisions). But if this is a float type, we have more work to do. % \def\xrdef#1#2{% \expandafter\gdef\csname XR#1\endcsname{#2}% remember this xref value. % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR#1\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0{#1}}% \fi } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readdatafile{aux}% \global\havexrefstrue \fi \closein 1 } \def\setupdatafile{% \catcode`\^^@=\other \catcode`\^^A=\other \catcode`\^^B=\other \catcode`\^^C=\other \catcode`\^^D=\other \catcode`\^^E=\other \catcode`\^^F=\other \catcode`\^^G=\other \catcode`\^^H=\other \catcode`\^^K=\other \catcode`\^^L=\other \catcode`\^^N=\other \catcode`\^^P=\other \catcode`\^^Q=\other \catcode`\^^R=\other \catcode`\^^S=\other \catcode`\^^T=\other \catcode`\^^U=\other \catcode`\^^V=\other \catcode`\^^W=\other \catcode`\^^X=\other \catcode`\^^Z=\other \catcode`\^^[=\other \catcode`\^^\=\other \catcode`\^^]=\other \catcode`\^^^=\other \catcode`\^^_=\other % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. % in xref tags, i.e., node names. But since ^^e4 notation isn't % supported in the main text, it doesn't seem desirable. Furthermore, % that is not enough: for node names that actually contain a ^ % character, we would end up writing a line like this: 'xrdef {'hat % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first % argument, and \hat is not an expandable control sequence. It could % all be worked out, but why? Either we support ^^ or we don't. % % The other change necessary for this was to define \auxhat: % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter % and then to call \auxhat in \setq. % \catcode`\^=\other % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other \catcode`\%=\other \catcode`+=\other % avoid \+ for paranoia even though we've turned it off % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % Make the characters 128-255 be printing characters. {% \count1=128 \def\loop{% \catcode\count1=\other \advance\count1 by 1 \ifnum \count1<256 \loop \fi }% }% % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 } \def\readdatafile#1{% \begingroup \setupdatafile \input\jobname.#1 \endgroup} \message{insertions,} % including footnotes. \newcount \footnoteno % The trailing space in the following definition for supereject is % vital for proper filling; pages come out unaligned when you do a % pagealignmacro call if that space before the closing brace is % removed. (Generally, numeric constants should always be followed by a % space to prevent strange expansion errors.) \def\supereject{\par\penalty -20000\footnoteno =0 } % @footnotestyle is meaningful for info output only. \let\footnotestyle=\comment {\catcode `\@=11 % % Auto-number footnotes. Otherwise like plain. \gdef\footnote{% \let\indent=\ptexindent \let\noindent=\ptexnoindent \global\advance\footnoteno by \@ne \edef\thisfootno{$^{\the\footnoteno}$}% % % In case the footnote comes at the end of a sentence, preserve the % extra spacing after we do the footnote number. \let\@sf\empty \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. % % Oh yes, they do; otherwise, @ifset (and anything else that uses % \parseargline) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. \hsize=\pagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox \floatingpenalty\@MM \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip \parindent\defaultparindent % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\hang}% \textindent{\thisfootno}% % % Don't crash into the line above the footnote text. Since this % expands into a box, it must come within the paragraph, lest it % provide a place where TeX can split the footnote. \footstrut \futurelet\next\fo@t } }%end \catcode `\@=11 % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarily, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @image. We use the macros from epsf.tex to support this. % If epsf.tex is not installed and @image is used, we complain. % % Check for and read epsf.tex up front. If we read it only at @image % time, we might be inside a group, and then its definitions would get % undone and the next image would fail. \openin 1 = epsf.tex \ifeof 1 \else % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get it from ftp://tug.org/tex/epsf.tex.} % \def\image#1{% \ifx\epsfbox\undefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing this stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names % If the image is by itself, center it. \ifvmode \imagevmodetrue \nobreak\bigskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \line\bgroup \fi % % Output the image. \ifpdf \dopdfimage{#1}{#2}{#3}% \else % \epsfbox itself resets \epsf?size at each figure. \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi \epsfbox{#1.eps}% \fi % \ifimagevmode \egroup \bigbreak \fi % space after the image \endgroup} % @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, % etc. We don't actually implement floating yet, we always include the % float "here". But it seemed the best name for the future. % \envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} % There may be a space before second and/or third parameter; delete it. \def\eatcommaspace#1, {#1,} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. % % BEWARE: when the floats start float, we have to issue warning whenever an % insert appears inside a float which could possibly float. --kasal, 26may04 % \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \thissection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\thissection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline{\scanexp\thiscaption}% \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline % % Space below caption. \vskip\parskip \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \atdummies % % since we read the caption text in the macro world, where ^^M % is turned into a normal character, we have to scan it back, so % we don't write the literal three characters "^^M" into the aux file. \scanexp{% \xdef\noexpand\gtemp{% \ifx\thisshortcaption\empty \thiscaption \else \thisshortcaption \fi }% }% \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % % place the captured inserts % % BEWARE: when the floats start floating, we have to issue warning % whenever an insert appears inside a float which could possibly % float. --kasal, 26may04 % \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \def\appendtomacro#1#2{% \expandafter\def\expandafter#1\expandafter{#1#2}% } % @caption, @shortcaption % \def\caption{\docaption\thiscaption} \def\shortcaption{\docaption\thisshortcaption} \def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} \def\defcaption#1#2{\egroup \def#1{#2}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \thissection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % and i18n. % @documentlanguage is usually given very early, just after % @setfilename. If done too late, it may not override everything % properly. Single argument is the language abbreviation. % It would be nice if we could set up a hyphenation file here. % \parseargdef\documentlanguage{% \tex % read txi-??.tex file in plain TeX. % Read the file if it exists. \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \input txi-#1.tex \fi \closein 1 \endgroup } \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? In the current directory should work if nowhere else does.} % @documentencoding should change something in TeX eventually, most % likely, but for now just recognize it. \let\documentencoding = \comment % Page size parameters. % \newdimen\defaultparindent \defaultparindent = 15pt \chapheadingskip = 15pt plus 4pt minus 2pt \secheadingskip = 12pt plus 3pt minus 2pt \subsecheadingskip = 9pt plus 2pt minus 2pt % Prevent underfull vbox error messages. \vbadness = 10000 % Don't be so finicky about underfull hboxes, either. \hbadness = 2000 % Following George Bush, just get rid of widows and orphans. \widowpenalty=10000 \clubpenalty=10000 % Use TeX 3.0's \emergencystretch to help line breaking, but if we're % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. We call this whenever the paper size is set. % \def\setemergencystretch{% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% \else \emergencystretch = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; % 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; % 7) physical page height; 8) physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \voffset = #3\relax \topskip = #6\relax \splittopskip = \topskip % \vsize = #1\relax \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin \pageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in \pagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{46\baselineskip}{6in}% {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.25 trim size. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {\voffset}{.25in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @smallerbook to reset parameters for 6x9 trim size. % (Just testing, parameters still in flux.) \def\smallerbook{{\globaldefs = 1 \parskip = 1.5pt plus 1pt \textleading = 12pt % \internalpagesizes{7.4in}{4.8in}% {-.2in}{-.4in}% {0pt}{14pt}% {9in}{6in}% % \lispnarrowing = 0.25in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .4cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{51\baselineskip}{160mm} {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \globaldefs = 0 }} % @pagesizes TEXTHEIGHT[,TEXTWIDTH] % Perhaps we should allow setting the margins, \topskip, \parskip, % and/or leading, also. Or perhaps we should compute them somehow. % \parseargdef\pagesizes{\pagesizesyyy #1,,\finish} \def\pagesizesyyy#1,#2,#3\finish{{% \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi \globaldefs = 1 % \parskip = 3pt plus 2pt minus 1pt \setleading{\textleading}% % \dimen0 = #1 \advance\dimen0 by \voffset % \dimen2 = \hsize \advance\dimen2 by \normaloffset % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper \message{and turning on texinfo input format.} % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \catcode`\~=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\+=\other \catcode`\$=\other \def\normaldoublequote{"} \def\normaltilde{~} \def\normalcaret{^} \def\normalunderscore{_} \def\normalverticalbar{|} \def\normalless{<} \def\normalgreater{>} \def\normalplus{+} \def\normaldollar{$}%$ font-lock fix % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), and another way in other fonts, % where something hairier probably needs to be done. % % #1 is what to print if we are indeed using \tt; #2 is what to print % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. % \def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Turn off all special characters except @ % (and those which the user can use as if they were ordinary). % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def~{{\tt\char126}} \chardef\hat=`\^ \catcode`\^=\active \def^{{\tt \hat}} \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \let\realunder=_ % Subroutine for the previous macro. \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def<{{\tt \less}} \chardef \gtr=`\> \catcode`\>=\active \def>{{\tt \gtr}} \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have \everyjob (or @setfilename) turn them on. % \otherifyactive is called near the end of this file. \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% \normalturnoffactive \otherbackslash } \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \realbackslash is an actual character `\' with catcode other, and % \doublebackslash is two of them (for the pdf outlines). {\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} % In texinfo, backslash is an active character; it prints the backslash % in fixed width font. \catcode`\\=\active @def@normalbackslash{{@tt@backslashcurfont}} % On startup, @fixbackslash assigns: % @let \ = @normalbackslash % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. % @def@normalturnoffactive{% @let\=@normalbackslash @let"=@normaldoublequote @let~=@normaltilde @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let<=@normalless @let>=@normalgreater @let+=@normalplus @let$=@normaldollar %$ font-lock fix @unsepspaces } % Make _ and + \other characters, temporarily. % This is canceled by @fixbackslash. @otherifyactive % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\' in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. % @gdef@fixbackslash{% @ifx\@eatinput @let\ = @normalbackslash @fi @catcode`+=@active @catcode`@_=@active } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These look ok in all fonts, so just make them not special. @catcode`@& = @other @catcode`@# = @other @catcode`@% = @other @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c page-delimiter: "^\\\\message" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @ignore arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 @end ignore edb-1.31/doc/version.texi0000644000175000017500000000005211016452257013511 0ustar ttnttn@set VERSION 1.31 @set UPDATED 2008-05-26 edb-1.31/doc/GNUmakefile.in0000444000175000017500000000413711016447333013615 0ustar ttnttn# GNUmakefile for EDB subdir "doc". # Copyright (C) 2007,2008 Thien-Thi Nguyen # # This file is part of EDB. # # EDB 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 3, or (at your option) any later # version. # # EDB 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 EDB; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. srcdir = @srcdir@ top_srcdir = @top_srcdir@ prefix = @prefix@ datarootdir = @datarootdir@ datadir = @datadir@ infodir = @infodir@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ mkinstalldirs = $(top_srcdir)/install-sh -d VERSION = @PACKAGE_VERSION@ LATEX = latex DVIPS = dvips PS2PDF = ps2pdf all: edb.info refcard.ps edb.info: edb.texi version.texi makeinfo -o $@ $< .tex.dvi: $(TEXI2DVI) $< .texi.dvi: $(TEXI2DVI) $< version.texi: $(top_srcdir)/configure @echo creating $@ @( echo '@set VERSION $(VERSION)' ; \ date -r $< '+@set UPDATED %F' ) > $@ %.dvi: %.tex refcard.version.tex $(LATEX) $< %.ps: %.dvi $(DVIPS) -t landscape $< $(RM) $*.{aux,log} %.pdf: %.ps $(PS2PDF) $< refcard.version.tex: $(top_srcdir)/configure @echo Creating $@ @echo '\def\versionnumber{$(VERSION)}' > $@ @date '+\def\year{%Y}' -r $< >> $@ @date '+\def\updated{%Y-%m-%d}' -r $< >> $@ prep-dist: rm -f *.{aux,cp,cps,dvi,fn,ky,log,pg,toc,tp,vr} clean: prep-dist rm -f *.ps *.pdf edb.info ii = install-info install: all $(mkinstalldirs) $(infodir) $(INSTALL_DATA) edb.info $(infodir) if ($(ii) --version && \ $(ii) --version 2>&1 | sed 1q | grep -i -v debian) \ >/dev/null 2>&1 ; then \ $(ii) --info-dir="$(infodir)" "$(infodir)/edb.info" || : ; \ else : ; fi installcheck: # GNUmakefile.in ends here edb-1.31/doc/edb.texi0000444000175000017500000063434011016451756012574 0ustar ttnttn\input texinfo @c %**start of header @setfilename edb.info @settitle EDB -- The Emacs Database @paragraphindent 0 @c %**end of header @c Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen @dircategory Emacs @direntry * EDB: (edb). The Emacs Database. @end direntry @copying Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. @end copying @syncodeindex tp cp @include version.texi @titlepage @title EDB Manual @subtitle The Emacs Database @author Michael Ernst @author Thien-Thi Nguyen @page @vskip 0pt plus 1filll Copyright @copyright{} 2004--2008 Thien-Thi Nguyen @insertcopying @end titlepage @c --------------------------------------------------------------------------- @node Top @top EDB Manual @ifinfo EDB is the Emacs Database. This file is the @value{UPDATED} Edition of the EDB Manual, corresponding to EDB @value{VERSION}. @quotation @insertcopying @end quotation @end ifinfo @menu * Introduction:: User Manual * Database mode:: * Database View mode:: * Database Edit mode:: * Searching:: * Sorting:: * Database Summary mode:: * Marking and hiding:: * Reports:: * Specifying the display format:: Programmer Manual * Specifying control:: * Record field types:: * Database file layout:: * How information is displayed:: * Customization:: * Database representation:: * Naming conventions:: * In case of trouble:: Indices * Function Index:: * Variable Index:: * Concept Index:: @detailmenu --- The Detailed Node Listing --- Introduction * Organization of this manual:: * Terminology and concepts:: * Invoking EDB:: * Example EDB session:: Database View mode * Moving around in the database:: * Changing to Database Edit mode:: * Undoing all changes to a record:: * Making changes permanent:: * Adding and removing records:: * Exiting database mode:: Database Edit mode * Exiting Database Edit mode:: * Undoing changes to a field:: * Moving from record to record:: * Moving from field to field:: * Movement within a field:: * Editing a field:: * Getting help:: Sorting * Sort interface:: * Sorting functions:: Marking and hiding * Setting the mark and hide bits:: * Movement among marked and hidden records:: * Details of hiding:: Specifying the display format * Changing display formats:: * Execution of format file eval expressions:: * Making additional data display buffers:: Specifying control * Interpreting control properties:: * Kinds of control property values:: * Control properties reference:: * New control example:: * Ongoing migration:: * Changing control properties at runtime:: * Example control file from scratch:: Record field types * Specifying a record field type:: * Predefined record field types:: * Record field attributes:: Database file layout * Data encoding:: * Internal file layout:: * Delimited file layout:: * Tagged file layout:: * Relational file layout:: * Nonregular file layout:: * Reading from disk:: Delimited file layout * How to specify delimited file layouts:: * Resolving ambiguities:: * Problems with end-of-file newlines:: Nonregular file layout * Nonregular database example:: How information is displayed * Display specifications:: * Predefined displaytypes:: * Enumeration displaytypes:: * Defining new displaytypes:: * Display specification optional parameters:: Customization * Auxiliary files:: * Hooks and customization functions:: * Global variables:: Hooks and customization functions * Read hooks:: * Database mode hooks:: * Record display hooks:: * Edit mode hooks:: * Display format change hooks:: Database representation * Mapping over the database:: * Manipulating records:: @end detailmenu @end menu @node Introduction @chapter Introduction EDB is a database program for GNU Emacs. It permits you to manipulate structured (or not-so-structured) data within Emacs and provides many of the usual database features, including: @itemize @bullet @item Flexible, customizable file layouts. Data may contain any character, including those used to delimit fields and records. Files read and written by the database may have arbitrary formats. @item Typed fields (e.g.@: integer, date, string); fields may also be subject to additional constraints (prime number, date before today, string that appears in some other record, etc.). @item Arbitrary data display formats for viewing records. Multiple display formats can be open on a database simultaneously, viewing the same or different records. The data display format can be automatically chosen based on the record's field values. @item Selective display of only those records of interest; others become temporarily invisible. @item Standard GNU Emacs editing commands, which work only within data fields and not on the surrounding text. @item Database summaries, which show in a single buffer one or more lines of information about each record. @item Sorting, with an easy-to-use interface for defining the sorting criteria; most sorting orders you would care about are easy to specify, but arbitrary ones are also permitted. @item Merging and reconciliation of databases. @item Reports generated from database information. @item Highly customizable via the underlying programming language, Emacs Lisp; many hooks and useful variables are provided to make this even easier. @end itemize EDB is more ambitious --- and therefore more complex --- than its forerunners (such as Forms Mode by Johan Vromans ). While other packages don't provide as much functionality as EDB, they may be more appropriate for simple needs. While EDB provides sophisticated functionality and is extensively customizable, it is not as powerful as some other database systems, and does not directly qualify as either ``relational'' or ``object-oriented.'' On the other hand, EDB may well meet your needs without being buzzword-compliant. (EDB extensions to provide a subset of the features of a relational or object-oriented database can and have been written.) @menu * Organization of this manual:: * Terminology and concepts:: * Invoking EDB:: * Example EDB session:: @end menu @node Organization of this manual @section Organization of this manual This manual contains two major parts. The first part describes how to use EDB to manipulate an existing database, and the second part describes how to design a new database. The first part --- which could be called the EDB User Manual --- first presents basic commands such as loading a database into memory, adding, deleting, and modifying records, and searching; then it describes more advanced features such as sorting, displaying record summaries, marking or ignoring certain records, and producing reports. The second part --- which could be called the EDB Programmer Manual --- describes the three forms that database information can take: when being manipulated by EDB, when stored on disk, and when displayed on the screen. Separate chapters discuss specifying each of these representations. The manual then goes on to discuss customization hooks and explains some of the lower-level implementation details that an advanced programmer may need to know. @cindex documentation to be deleted @cindex implementation details @cindex details, implementation Note that these implementation details may change or disappear entirely, after first becoming undocumented. Such cases are marked with @kbd{Documentation for FOO is to be deleted by EDB X.Y}, where X.Y is a version number of a future EDB release. @macro scadenza{v,x} @emph{NOTE}: Documentation for \x\ is to be deleted by EDB \v\. @end macro @node Terminology and concepts @section Terminology and concepts A @dfn{database} is a collection of @dfn{records} kept in memory, each of which is comprised of various @dfn{fields}. A record's fields are usually all related to some central object or concept; for instance, they might describe various information about a particular person such as name, address, and phone number. A field's meta-information --- for example name, default value, methods for representing the value between memory/disk/display contexts, behavior on update, constraints, and so on --- is collectively called its @dfn{fieldtype}. All records of a database have the same structure (the number and order of the fieldtypes are the same), though typically different records have different information in the fields. EDB permits database records to be viewed, edited, and manipulated in a structured way. When a database is @dfn{in memory}, there is at least one @dfn{data display buffer} associated with it, showing a single record --- the @dfn{current record} --- using a particular @dfn{display format}. This buffer can be in Database View or Database Edit mode. A display format is a template, comprising @dfn{inter-field text} embedded with at least one @dfn{display specification} (@dfn{displayspec}, for short). The displayspec associates a field name with a @dfn{displaytype}, which controls how a particular fieldtype is to be rendered in a buffer (inter-field text is rendered as-is). Each data display buffer may have a dependent @dfn{summary buffer} showing selected fields of all records. Moving from one record to another in the summary buffer updates the data display buffer to synchronize the current record. (However, moving in the data display buffer does not update the summary buffer.) Killing a data display buffer kills its associated summary buffer (if any), although the reverse is not true. When the last data display buffer associated with a database is killed, EDB forgets the database; it is no longer in memory. Collectively, all the information outside of the data proper --- display formats, fieldtypes, and so on --- is called the @dfn{control}, to borrow the hardware designer's terminology and awareness of the duality of control signals versus datapath: @quotation If we believe in data structures, we must believe in independent (hence simultaneous) processing. For why else would we collect items within a structure? Why do we tolerate languages that give us the one without the other? ---Alan Perlis @end quotation [I believe Perlis is saying that the computation model for hardware, where everything happens in parallel, is pretty interesting. Maybe EDB is not so interesting, but that's just a SMOP away... ---ttn] @node Invoking EDB @section Invoking EDB @cindex invoking EDB @cindex files used by EDB To use EDB, you need to establish a connection to a control source and a data source, the former describing how EDB should handle the latter, either with the command @code{edb-interact}, or with the command @code{db-find-file}. The first command made its debut in EDB 1.26 and is destined to evolve towards its final form for EDB 2.x; it is recommended over the second one for reasons too complicated to explain here (@pxref{Reading from disk}, instead). Suffice to say that the @code{db-find-file} approach will not be available in EDB 2.x. In either case, to arrange for the commands to be autoloaded, add this form to your @file{~/.emacs} file: @lisp (let ((el "database") (blurb "Emacs Database")) (autoload 'edb-interact el blurb t) (autoload 'db-find-file el blurb t)) @end lisp Now, when you start up Emacs, you will already be able to execute @code{edb-interact} and/or @code{db-find-file}; EDB will be loaded automatically. @subsection Connecting with @code{edb-interact} @cindex @file{.edb} files @cindex control file @cindex control buffer Control information is usually saved in a file, but may also be taken directly from the current buffer. This @dfn{control file} (or perhaps @dfn{control buffer} as the case may be) is the first argument to the command @code{edb-interact}. The second argument specifies the data file. @deffn {Command} edb-interact control data Open a connection to the @var{control} (.edb) and @var{data} files. @var{control} may be a buffer whose contents are to be parsed as a @file{.edb} file. @var{data} may be nil, in which case the EDB searches for a file whose stem is the same as @var{control}'s (or its @code{buffer-file-name} if @var{control} is a buffer), with extension one of @file{.data}, @file{.dat}, or the empty string (no extension), in that order. Once the connection is open, read in @var{data} and switch to the data display buffer. However, if @var{data} is already in memory, simply switch to its (first) data display buffer. @end deffn You can use a properly constructed control file (or buffer) with multiple data sources. To create a new database, the easiest way is to copy one of the @file{.edb} files in the distribution and adapt it to your needs. @xref{New control example}, for an example. @subsection Connecting with @code{db-find-file} @cindex @file{.dat} file suffix @cindex @file{.fmt} file suffix @cindex @file{.dba} file suffix @cindex three file types used by EDB You need three files to run EDB the ``old'' (1.x only) way: a data file, a format file, and an auxiliary file. The data file (usual suffix @file{.dat}) contains the information that makes up the database. The format file (usual suffix @file{.fmt}) specifies how the fields of a particular record appear in the data display buffer, where you may view or edit one record at a time. The auxiliary file (usual suffix @file{.dba}) contains additional information about the database, such as the number of fields in each record, the layout of the data file (including what characters or strings serve as field and record separators), customizations, etc. A fourth type of file is the report format file, which is a format file used in generating reports printed on the screen, to a file, or to a printer; @pxref{Reports}. Different databases may share format and auxiliary files. For examples of data, format, and auxiliary files, see the @file{examples} subdirectory of the EDB distribution. You can combine the format and auxiliary files (by placing the auxiliary file information at the end of the format file, in the local variables section), but for simplicity we will consider the two files separately. There may be many different ways to lay out a record on the screen, so a database could have many different format files; for the time being we will concentrate on the format file which is used first, which is called the primary format file, even though it might not be the one that is used most often. @cindex reading a database from disk @cindex starting up EDB When invoking the database, you typically only need to name the data file; the names of the others are inferred from its name (@pxref{Auxiliary files}) or may be mentioned explicitly by it. The @code{db-find-file} command loads the database into memory: @deffn {Command} db-find-file [filename [promptp]] Read a database from @var{filename}. If the database file doesn't specify a format and the format file can't be inferred from @var{filename}, then prompt for it, too. Always prompt for the format file if prefix argument @var{promptp} is non-@code{nil}. If the database is already read in and @var{promptp} is @code{nil}, the existing database buffer is merely selected. When called non-interactively, argument @var{promptp} may be a string, the name of a format file to use. @end deffn @cindex saving to disk @cindex writing to disk You can use @code{db-save-database} and @code{db-write-database-file} (normally bound to @kbd{C-x C-s} and @kbd{C-x C-w}, respectively, in Database View mode) to save databases in memory to the file from which they were read or to an arbitrary file. @node Example EDB session @section Example EDB session Here is a small tutorial that steps through a typical EDB session: connecting to a single control and a single data source, moving from record to record in the data display buffer, creating a summary buffer, sorting the records, writing the changed data (if any) to disk, and finally disconnecting. Each step is a command or a series of commands to type into Emacs (sometimes with trailing @key{RET} implied). Additionally, you can type @kbd{C-h m} in each of the buffers for more information. @table @kbd @item C-x C-f skram/retired.edb @itemx M-x edb-interact This visits a control file in the distribution and initiates a connection. You can simply type @key{RET} when Emacs asks for the control file (at the first prompt) to use the current buffer. Note that you could have specified the control file directly to @code{edb-interact} without visiting it; we present it in two steps to give you a chance to look over its contents. The distribution also includes the file @file{retired.data} in the same directory, so you can type @key{RET} when Emacs asks for the data source (at the second prompt) to have EDB find it automatically. Once the data is in memory, Emacs switches to its data display buffer, which is in Database View mode, which is read-only and does not permit editing. @xref{Database mode}, @xref{Database View mode}. @item n @itemx p These update the buffer with the next or previous record, respectively. @xref{Moving around in the database}. @item TAB @itemx C-n This moves point to the first field and switches to Database Edit mode. @xref{Changing to Database Edit mode}, @xref{Database Edit mode}. Once you are on a field, printing characters insert themselves and the other usual editing commands work as well. @kbd{TAB} moves to the next field, and @kbd{C-n} moves to a field on the next line (or to the next line of this field, if it spans multiple lines). @xref{Moving from field to field}, @xref{Movement within a field}. @item M-TAB @itemx C-p Like @kbd{TAB} and @kbd{C-n}, but move backward by fields or lines. @item C-c C-c This returns to Database View mode from Database Edit mode. If you made any changes, you can type @key{RET} now to accept the changes, or @kbd{C-x u} to undo them. @item h This displays a summary (also known as @dfn{headers}) of all the records of the database. You can move around in the summary buffer using ordinary movement commands, and the record under point will be displayed in the data display buffer. Use @kbd{v} or @kbd{e} to return to the data display buffer; @kbd{v} puts you in Database View mode and @kbd{e} puts you in Database Edit mode. @xref{Database Summary mode}. @item S (Note: uppercase.) From Database View mode, this invokes the database sort interface, which permits easy specification of how records should be sorted. Type @kbd{M-n} and @kbd{M-p} to drag a field up (more important) or down (less important). Type @key{RET} to perform the sort and return to the data display buffer. @xref{Sorting}. @item C-x C-s This saves to disk any changes you have made to the data. @item + This creates a new data display buffer. @item x This kills the current data display or summary buffer. In the latter case, Emacs switches to the associated data display buffer. You are offered the chance to save the changes you have made. @end table For invocation with @code{db-find-file}, the tutorial is still applicable if you use @kbd{M-x db-find-file examples/forms-demo.dat} for the first step instead of the @kbd{C-x C-f} and @kbd{M-x edb-interact}. @node Database mode @chapter Database mode A single database record (typically the @dfn{current record}) is viewed in a data display buffer.@footnote{The data display buffer was previously called the format buffer; this is why all of the variables and functions relating to it start with the @code{dbf-} prefix.} The layout and formatting of the data display buffer --- where and how the fields of the current record are shown, and what fixed explanatory text surrounds them --- is specified by a data display format. Only the database fields can be edited; the explanatory text is fixed. @xref{Specifying the display format}, to create a new data display format. @xref{Making additional data display buffers}, to create a new data display buffer (with the same or a different data display format). @xref{Database Summary mode}, to view summary information about all database records at once. @cindex editing database files @cindex database files, editing @cindex files, editing database Database mode has two basic submodes, Database View mode (@pxref{Database View mode}) and Database Edit mode (@pxref{Database Edit mode}). These modes are used, respectively, when examining or manipulating records and when changing information in a particular record. Keystrokes have different meanings in these two modes. In Database View mode no editing may be done, and many printable characters are redefined to make manipulation of the database easy (for instance, @kbd{n} moves to the next record). In Database Edit mode a field of the current record is being edited; most printable keys insert themselves, and other editing and movement commands work in the ordinary way. In the data display buffer, where database records are ordinarily viewed and edited, one of these two modes is always in effect. (You may be tempted to directly edit a raw database file in its on-disk layout. Do so at your own risk, and never change a database buffer out of Database mode.) @cindex mode line The mode line indicates which mode you are in. It looks something like: @example -***- machine-dbase (Database Edit Abbrev 42/431)---All------------ @end example The mode line consists of three modification indicators, the name of the database file being manipulated (in this case, @file{machine-dbase}), mode information within parentheses, and the usual percentage-of-screen-visible indicator. The mode information consists of the database submode (such as View, Edit, or Summary), any minor modes which are turned on (such as Abbrev mode), the number of the current record, and the total number of records in the database. Ordinarily the Emacs mode line contains only one modification indicator consisting of two dashes (not modified), asterisks (modified), or percent signs (read-only). The EDB mode line contains three modification indicators, one each for the database, the displayed record, and the current field. The field indicator is @samp{*} if the field under point has been modified, @samp{-} if it has not, and @samp{%} if it is read-only or if no field is under point (for instance, if the data display buffer is in Database View mode rather than Database Edit mode). The database is modified only when a changed record is written into it; changes to the current record do not immediately affect the database proper. This permits such modifications to be conveniently undone. @xref{Undoing all changes to a record}. @xref{Making changes permanent}. Thus, the displayed record may be modified without the database being modified, since the database is considered modified only when the current record has been processed and the resulting value placed in the database. A similar situation exists for the current field of the current record. (@xref{Undoing changes to a field}.) Do not attempt to directly change the major mode of a database buffer. If a database buffer is placed in another mode, the database functions will cease working (they refuse to operate on non-database buffers, since the consequences of such action could be severe); for instance, you may be unable to save any of your work due to errors raised while EDB tries write to its buffers to disk. Furthermore, EDB makes assumptions about where point is located in Database View and Database Edit modes; violating these can cause changes to the current record to be lost. @node Database View mode @chapter Database View mode @cindex Database View mode @cindex View mode, Database The data display buffer is in Database View mode whenever field information is not being edited. Most commands to move from record to record and to manipulate records (sorting, printing reports, showing summaries, etc.) are performed in Database View mode. Basic operations are described here; more complicated ones, such as searching (@pxref{Searching}), are given sections of their own. @menu * Moving around in the database:: * Changing to Database Edit mode:: * Undoing all changes to a record:: * Making changes permanent:: * Adding and removing records:: * Exiting database mode:: @end menu @node Moving around in the database @section Moving around in the database @cindex moving from record to record @table @kbd @item n @deffn {Command} db-next-record [arg] Go to the @var{arg}th next record. In that record, go to the current field, if any. @end deffn @item p @deffn {Command} db-previous-record [arg] Go to the @var{arg}th previous record. In that record, go to the current field, if any. @end deffn @item < @itemx M-< @deffn {Command} db-first-record [arg] Show the database's first record. With optional prefix argument, ignore hiding. @end deffn @item > @itemx M-> @deffn {Command} db-last-record [arg] Show the database's last record. With optional prefix argument, ignore hiding. @end deffn @item j @deffn {Command} db-jump-to-record arg [respect-hiding] Show the database's @var{arg}th record. Hiding is ignored unless optional argument @var{respect-hiding} is specified. @end deffn @end table There are two special hybrid commands that show more of the current record if there's more to see and otherwise show the next (or previous) record. @table @kbd @item @key{SPC} @deffn {Command} db-next-screen-or-record [arg] Go to the @var{arg}th next screenful of this display, or to the @var{arg}th next record, if this is the last screenful of this display. If point is in the summary buffer and the data display buffer is not visible, then move to the next record. @end deffn @item @key{DEL} @deffn {Command} db-previous-screen-or-record [arg] Go to the @var{arg}th previous screenful of this display, or to the @var{arg}th previous record, if this is the first screenful of this display. If point is in the summary buffer and the data display buffer is not visible, then move to the previous record. @end deffn @end table @node Changing to Database Edit mode @section Changing to Database Edit mode When in Database View mode, you cannot edit the fields of the record being displayed. In order to do so, change to Database Edit mode and move to the field you wish to edit. You can click the mouse on the field you wish to edit, or move to the first or last field (and from there to the desired field) via the following keystrokes: @table @kbd @item TAB @itemx C-n @itemx e @deffn {Command} db-first-field Move to first field. @end deffn @item C-p @itemx M-TAB @deffn {Command} db-last-field Move to last field. @end deffn @end table @node Undoing all changes to a record @section Undoing all changes to a record @cindex undoing changes to a record @cindex reverting changes to a record @table @kbd @item C-x u @deffn {Command} db-revert-record Set the record to be the same as the corresponding one in the database. In other words, undo any changes made since entering this record. @end deffn @item C-x r @deffn {Command} db-revert-database Replace the database in memory with the data on disk. This undoes all changes since the database was last saved. @end deffn @end table You can also undo changes to the current field; @xref{Undoing changes to a field}. @node Making changes permanent @section Making changes permanent @cindex making changes permanent @cindex changes, making them permanent @cindex committing changes @cindex changes, committing them @cindex accepting changes @cindex changes, accepting them You edit a copy of a database record; the database itself is not changed until you commit the changes. This occurs automatically whenever any command causes a different record to be displayed, when the database is saved, when a report is generated, and so forth. It does @emph{not} occur when you switch from Database Edit mode to Database View mode, though the field modification flag (in the mode line) will become a percent sign and the record modification flag, an asterisk. When the record is committed, the record modification flag becomes a dash and the database modification flag becomes an asterisk. You can manually install the current record, as modified, into the database. @table @kbd @item @key{RET} @deffn {Command} db-accept-record Install the current record in the database; make any changes permanent. @end deffn @end table Committing a record makes the changes permanent only insofar as they become part of the in-memory representation of the database. The on-disk version is not affected unless you overwrite it by using @code{save-buffer} or @code{write-file}, or otherwise indicate that the database should be written to disk (say, by responding affirmatively to a question about saving the database). @node Adding and removing records @section Adding and removing records @cindex adding a record @cindex inserting a record @cindex deleting a record @cindex removing a record @cindex killing a record @table @kbd @item a @itemx i @deffn {Command} db-add-record [append] Add a new record to the database immediately before the current record. Prefix arg @var{append} means to add after the last record, instead. After adding, move point to the new record's first field and switch to Database Edit mode. @end deffn @item c @deffn {Command} db-copy-record [arg] Insert a copy of the current record in the database immediately after it. The second of the two records is made the current record. With a prefix argument, inserts that many copies. @end deffn @item o @deffn {Command} db-output-record-to-db database Copy (output) the current record to @var{database}. @var{database} must be read in and compatible with the current database. @end deffn @item d @itemx k @deffn {Command} db-delete-record [arg] Remove the current record from the database. With a prefix argument, do not verify. @end deffn @end table @node Exiting database mode @section Exiting database mode @cindex exiting database mode @cindex quitting database mode @cindex killing a database buffer @table @kbd @item q @deffn {Command} db-quit Quit editing the database for now; bury its buffers. @end deffn @item x @deffn {Command} db-kill-buffer [noask] Kill the data display buffer and any associated summary buffer. Offer to save any changes. Prefix arg means don't offer. @end deffn @item X @deffn {Command} db-kill-all-buffers [noask] Kill all buffers associated with the current database. Offer to save any changes. Prefix arg means don't offer. @end deffn @end table For backward compatability, there is also the command @code{db-exit}. @deffn {Command} db-exit [kill] Be done with the database; like @code{db-quit}, but offer to save any changes. With prefix argument, call @code{db-kill-all-buffers} after saving changes. @end deffn @node Database Edit mode @chapter Database Edit mode @cindex Database Edit mode @cindex edit mode The database is @dfn{modifiable} if either it is a new database, not associated with any file, or if it is read from a file that is modifiable (i.e., satisfies @code{file-writable-p}). The database being not modifiable does not prevent you from entering Database Edit mode, only from making changes while in Database Edit mode. You can toggle or set this status bit with @code{db-toggle-modifiable-p}, normally bound to @kbd{C-x C-q} in Database View, Database Edit, and Database Summary modes. @deffn {Command} db-toggle-modifiable-p [arg] Toggle whether the database may be modified. With a nonzero prefix argument, set it modifiable. With a zero prefix argument, set it non-modifiable. @end deffn The data display buffer is in Database Edit mode whenever a field of the current record is being edited. All printing characters insert themselves, and the usual editing commands can be performed on the field contents. It is also possible to move from field to field and from record to record, and to perform other operations on the database, though the commands available in Database View mode are richer. In Database Edit mode, point is always in the field currently being edited. The database is not modified as soon as changes are made in Database Edit mode. Rather, a copy of the record in question is displayed and edited, and only when you move to a new record, initiate some other global action (not specific to the edited record), or explicitly commit the changes (@pxref{Making changes permanent}). This permits easier undoing of incorrect modifications. In order to perform most record-level operations, you switch to Database View mode, and then perform them there. Several commonly used commands, however, such as searching and moving from record to record, are accessible directly from Database Edit mode. Commands that move from field to field check the validity of the current field before moving off it; commands that move from record to record do this as well, then make any changes in the current record permanent (though the database file on disk is not changed). Basic operations are described here; more complicated ones are given sections of their own. @menu * Exiting Database Edit mode:: * Undoing changes to a field:: * Moving from record to record:: * Moving from field to field:: * Movement within a field:: * Editing a field:: * Getting help:: @end menu @node Exiting Database Edit mode @section Exiting Database Edit mode @table @kbd @item C-c C-c @deffn {Command} db-view-mode [arg] Switch to Database View mode. With an argument, toggle between Database View and Database Edit modes. @end deffn @end table @node Undoing changes to a field @section Undoing changes to a field @cindex undoing changes to a field @cindex reverting changes to a field You can undo changes to the current field via Emacs' usual undo facility; use @kbd{C-x u} or @kbd{C-_} to undo changes made since entering the current field. You can also revert the current field to its original value; this is useful if you made a change, moved off the field, and then moved back onto it. @table @kbd @item C-x U @deffn {Command} db-revert-field Undo any changes made since entering this field. Replace the onscreen text in this field with that of the underlying record. A similar effect can be had by invoking @kbd{C-x u} multiple times. @end deffn @end table From Database View mode, you can simultaneously revert every modified field of a record to its original value; @xref{Undoing all changes to a record}. @node Moving from record to record @section Moving from record to record The commands for moving to the next and previous records make any changes to the current record permanent. @xref{Moving around in the database}. @node Moving from field to field @section Moving from field to field @cindex moving from field to field @table @kbd @item TAB @deffn {Command} db-next-field [arg] Move to @var{arg}th next reachable field, wrapping if necessary. When called interactively, @var{arg} defaults to 1. @end deffn @item M-TAB @deffn {Command} db-previous-field Move to @var{arg}th previous reachable field, wrapping if necessary. When called interactively, @var{arg} defaults to 1. @end deffn @item M-< @itemx M-> Move to the first or last field (@pxref{Changing to Database Edit mode}). @end table Also see the keystrokes @kbd{C-n} and @kbd{C-p}, described below. @node Movement within a field @section Movement within a field All Emacs cursor motion commands retain their standard meanings, except that they do not move outside the field. The line-movement commands have slightly changed meanings: if the motion would take the cursor out of the current field, then they move to the next field. @table @kbd @item C-n @deffn {Command} db-next-line-or-field [arg] Move to @var{arg}th next line. If that would move out of the current field, move to the closest field to that, but not the current one, wrapping if necessary. @end deffn @item C-p @deffn {Command} db-previous-line-or-field [arg] Move to @var{arg}th previous line. If that would move out of the current field, move to the closest field to that, but not the current one, wrapping if necessary. @end deffn @end table @node Editing a field @section Editing a field Many Emacs editing commands retain their standard meanings; for instance, printing characters insert themselves and deletion commands work as usual, except that they do not make changes outside the field; among these are: @table @kbd @item C-d @code{delete-char} @item @key{DEL} @code{backward-delete-char} @item M-d @code{kill-word} @item M-@key{DEL} @code{backward-kill-word} @item C-k @code{kill-line} @end table @node Getting help @section Getting help @cindex help for record fields You can get some information about the current field, such as what type of value it expects or what its contents signify, by using the following command. @table @kbd @item M-? @deffn {Command} db-field-help Display help for current field in the echo area. @end deffn @end table @node Searching @chapter Searching @cindex searching A useful and commonly used database operation is searching for records that meet some criteria: for instance, finding a particular record or indicating that following operations should only apply to records that correspond to an address in greater Boston. EDB provides several functions to support such operations. @section Search commands @cindex search commands To perform a search pertaining to the contents of only one field, move to that field and use the following command: @table @kbd @item M-s @deffn {Command} db-search-field Search for occurrences of @var{pattern} in the current field of any record. Finds the first match after the current record; wraps around automatically. With prefix argument, marks all matches in addition to going to the first one. If hiding is in effect, hidden records are ignored. @end deffn @end table The same keystroke in Database View mode permits specification of patterns which depend upon the contents of several fields: @table @kbd @item s @itemx M-s @itemx M-S @deffn {Command} db-search @code{db-search} is not yet implemented; use @code{db-search-field} instead. In a future version of EDB, @code{db-search} will permit searching on all fields of a record simultaneously. @end deffn @end table For a description of marking, @xref{Marking and hiding}. @section Search patterns @cindex search patterns Search patterns can be as simple as a datum to match exactly or as complicated as the conjunction, disjunction, and negation of tests to be performed on field contents. @subsection Basic patterns A basic search pattern has the same form as the data that is kept in the field; for instance, to search in a string field for a particular string, use that string; to search for the date March 14, 1967, use @samp{3/14/67} or @samp{14 March 1967} or any other accepted date format. A basic pattern is treated somewhat more richly than a literal, however. In a string field, typing a string results in a match for any element which contains it as a substring; typing @samp{ail}, without the quotes of course, matches both @code{"ailment"} and @code{"fail"}. In a date field, @samp{3/67} matches any date in March of 67, not just those March 67 dates which specifically exclude a day of the month. @subsection Comparisons @cindex <, in search pattern @cindex >, in search pattern @cindex =, in search pattern A search pattern may also be a comparison prefix (<, >, or =) plus a datum which is treated exactly like any other element of that field. In a string field, @samp{3/14} matches dates after March 14 in any year, and @samp{=3/67} matches only dates in March 67 whose day of month is not specified. For more information about the interpretation of patterns, see the documentation for the particular types. @subsection Logical connectives More complicated patterns can be built up out of simpler ones via the logical connectives AND, OR, and NOT. These work in the obvious way. One pattern which finds any date between the ides of March and Christmas, inclusive, is @samp{> 3/14 AND < 12/26}; two patterns which find dates except March 14 are @samp{NOT 3/14} and @samp{< 3/14 OR > 3/14}. To find strings that either contain the substring @code{"ail"} or start with a, b, or c, use @samp{ail OR < d}. The precedence of these connectives is: NOT, which is most tightly bound to its test, then OR, then AND. There are no provisions for grouping or otherwise overriding this ordering. Connectives (and REGEXP, described below) consume all surrounding spaces and tabs. @subsection Other pattern operations One other pattern operation of interest is the regexp operator for string fields. This is invoked by either using REGEXP with surrounding spaces, or / without a trailing space. For instance, @samp{/^[ace]} matches any string field starting with a, c, or e; @samp{/.} matches any nonblank string field; and @samp{NOT REGEXP a.*b.*c} matches any string which does not contain the letters a, b, and c in order. This last example shows that EDB's search commands are more powerful than general regular expression searching. @node Sorting @chapter Sorting @cindex sorting Sorting a database reorders its records without changing the contents of any particular record. For instance, it might be convenient to arrange an address database sometimes alphabetically by last name, sometimes by ZIP code, and sometimes by some other criteria. @menu * Sort interface:: * Sorting functions:: @end menu @node Sort interface @section Sort interface From a data display buffer in Database View mode, you can specify a particular record ordering using @code{db-sort}. @table @kbd @item S @deffn {Command} db-sort [arg] Switch to the sort interface buffer. With a prefix argument, don't confirm the sort order. @end deffn @end table Ordinarily, calling this function invokes the sort interface, an easy-to-use tool for specifying which fields should be treated as sort keys, and in what order. In a database whose records have fields @samp{firstname}, @samp{lastname}, @samp{address}, @samp{city}, and @samp{zip}, and in which records should first be sorted on @samp{lastname} in increasing order, then on @samp{firstname} in @emph{decreasing} order, ignoring the other fields entirely for the purposes of the sort, the sort interface display would look like @example ==== Significant fields: lastname increasing firstname decreasing ==== Nonsignificant fields: address increasing city increasing zip increasing ==== Hidden records to end: No @end example In addition to which fields should be sorted by, the sort interface permits specification of how hidden records should be treated. @table @kbd @item t @deffn {Command} dbsi-toggle-hidden-to-end Toggle a flag that controls whether hidden records should all be placed at the end of the sorted order or should be sorted according to the same criteria as non-hidden records. @end deffn @end table To change the relative order of fields, and whether they're significant or not, use the following commands. @table @kbd @item C-k @deffn {Command} dbsi-kill-line Move field on current line to the top of the nonsignificant list. This can also be used within the nonsignificant list to reorder it. @end deffn @item C-y @deffn {Command} dbsi-yank-line Yank the field from the top of the nonsignificant list. Insert it before the current line. Prefix arg means point doesn't move. @end deffn @item M-p @itemx M-n In the list of significant fields, ``drag'' the field under point up (more important) and down (less important), respectively. @end table To specify how a particular field should be ordered, use the following commands. @table @kbd @item i @deffn {Command} dbsi-increasing Specify that the field at point should use an increasing ordering. @end deffn @item d @deffn {Command} dbsi-decreasing Specify that the field at point should use a decreasing ordering. @end deffn @item o @deffn {Command} dbsi-ordering-function Specify an ordering function for the field at point. An @dfn{ordering function} returns -1, 0, or 1 depending on whether its first argument is less than, equivalent to, or greater than its second argument. @end deffn @item s @deffn {Command} dbsi-sorting-function Specify a sorting function for the field at point. A @dfn{sorting function} returns @code{t} if its first argument is less than its second argument and @code{nil} otherwise. @end deffn @end table Each database has a default sort order specified by the @code{:field-order} control property (@pxref{Control properties reference}), used when setting up the sort interface (and is used for sorting when no other ordering information is specified). When you exit the sort interface, the database's default ordering can be set to the ordering depicted on the screen (see below). Each data display buffer also has a default sort order; the database's default order is ignored if a local value is chosen using the sort interface. Setting the database's sort order automatically clears the local value. The following commands are used to exit the sort interface; most of them also cause the database to be sorted. Some of them set the default ordering for the database or the data display buffer. @table @kbd @item @key{RET} @itemx C-c C-c @deffn {Command} dbsi-use-ordering-make-database-default Use the current ordering to sort, and make it the default for future sorts of this database. Display a warning if there are killed, non-yanked fields. @end deffn @item A @itemx U @deffn {Command} dbsi-use-ordering-make-buffer-default Use the current ordering to sort, and make it the default for future sorts in this data display buffer only. Display a warning if there are killed, non-yanked fields. @end deffn @item a @itemx u @deffn {Command} dbsi-use-ordering Use the current ordering for this sort only. @end deffn @item ! @deffn {Command} dbsi-this-field-only Sort according to only the field at point. All editing of other fields is ignored. @end deffn @item q @deffn {Command} dbsi-quit Abort the sort and exit the sort interface (@code{dbsi-quit}). @end deffn @item c @deffn {Command} dbsi-quit-clear-buffer-default Clear the default sort order for this buffer and exit the sort interface without sorting. In the future, the default sort order will come from the database. @end deffn @end table The sort interface returns a field priorities list to be used when sorting. Sorting does not ordinarily mark the database as modified, because not the data itself, but only the way it is arranged, has been changed. If you set @code{db-sort-modifies-p} to non-@code{nil}, then whenever a database is sorted (even if the resulting order is the same as the original one), the database is marked as modified. @defvar db-sort-modifies-p If non-@code{nil}, then sorting a database marks it as modified too. @end defvar When using control properties, you should use a @code{:locals} variable by the same name. @node Sorting functions @section Sorting and ordering functions @cindex sorting functions @cindex ordering functions In order to specify the relative order of two field values (for the same field, but from different records), you provide a sorting function, an ordering function, or both. If only one is provided, the other is automatically generated from it. In any event, only one of them is used for a given field on any particular sort. A sorting function takes two field values as arguments and returns @code{t} if its first argument is less than its second argument (that is, the first argument appears previous to the second in the sorted order). The sorting function returns @code{nil} if the arguments are equal or if the first argument is greater than the second (appears later in the sorted order). An ordering function, on the other hand, returns complete information about the relative order of its two arguments: it returns -1, 0, or 1 depending on whether its first argument is less than, equivalent to, or greater than its second argument. Use of an ordering function can result in fewer comparisons in some cases, because it returns more information. This is worthwhile if a significant amount of processing is required before the comparison is done. For example, suppose that two addresses are being carefully checked for equality and some of the steps leading up to that are expansion of abbreviations, standardization of spelling, capitalization, and spacing, etc.; then it is better to return the exact relative ordering than to possibly require another time-consuming operation to determine it. If it is possible to canonicalize the values beforehand, that may be even more efficient, but that is not always possible; consider the case of a small (but tedious to extract) part of the information in each field being compared. @node Database Summary mode @chapter Database Summary mode @cindex Database Summary mode @cindex summary mode A summary is a listing containing abbreviated information about every record; it permits many records to be viewed at once. This is available in Database View mode via the following command: @table @kbd @item D @itemx H @itemx h @deffn {Command} db-summary Display a summary (or directory) of all database records according to the value set by @code{dbf-set-summary-format}. The summary appears in a separate buffer. When called from the summary buffer, this updates the summary. @end deffn @end table When a summary is created, the summary display format appears in the summary buffer once for each record, with appropriate values substituted for its display specifications. The entire format is indented by two characters; the first and second columns contain @samp{+} and @samp{[}, respectively, if the record is marked or hidden. @xref{Marking and hiding}. @xref{Details of hiding}. The summary buffer is not updated whenever a record value changes; in the interest of efficiency, it remains as is until the next @code{db-summary} command is issued, at which time the summaries are redisplayed after all, some, or none of them have been recomputed. For the same reason, when a single mark or hide bit changes, the summary is updated; when many change, it is usually not. When point is in the summary buffer, the associated data display buffer (nearly) always displays the record under point. (Some Emacs commands can move point without EDB noticing.) Movement in the summary buffer is by any of the ordinary Emacs commands, including searching. Most Database View mode commands also work in the summary buffer. The summary display format defaults to the first non-literal line in the database display format --- that is, the first line which contains a display specification. @cindex summary format, setting Summary display formats can display information any way that an ordinary display format can, including showing more than one field of the record in question or spanning several lines. The only restriction is that the summary display format must cover a specific number of lines: each display specification must have its @code{min-height} and @code{max-height} slots set to equal values. For more information about display formats, @xref{How information is displayed}. The following command may appear in a format file or an auxiliary file, or it can be invoked directly. When it appears as an Emacs Lisp form, remember the special meaning of the backslash character and double it where necessary. @deffn {Command} dbf-set-summary-format summary-format Specify the format used in the Database Summary buffer. Argument @var{summary-format} is a string containing display specifications. Call this in the data display buffer, or in a format file or auxiliary file. @end deffn @node Marking and hiding @chapter Marking and hiding @cindex marking @cindex hiding @cindex selecting only some records The marking facility permits operations to be performed on only certain records of a database. For instance, to create a report which describes only some of the database records, you would first mark the records of interest. Then you would call @code{db-report} with a prefix argument (do so by pressing @kbd{C-u} first), or would make optional second argument @var{markedp} non-@code{nil}. See the documentation of the individual operations to see whether they support operation on only the marked records. The hiding facility also restricts attention to a subset of the current database. It is similar to Outline mode in that it makes some records temporarily invisible. Hiding is useful when you wish to concentrate on a subset of the database without being distracted by other records that may be present. By default hidden records are skipped by the record-motion commands, excluded from searches and reports, and ignored by most other operations. Mark and hide bits are associated only with the in-memory version of a database; they are not saved when you save a database, and are always unset (boolean false) when a database is read in. (When a database is written to disk, although the disk version of the data does not contain the mark and hide information, that information is not lost from the working copy of the database.) This behavior is a feature, not a bug. Marking and hiding are intended to help you temporarily group database records for operations upon them; if there is information that cannot be recreated from a record's fields, then you should consider adding another field for that information. On the other hand, mark or hide criteria may be complicated. If such a pattern is used often, then you may wish to write a function to set the bits appropriately, which function could be bound to a keystroke or automatically executed when the database is read in. @menu * Setting the mark and hide bits:: * Movement among marked and hidden records:: * Details of hiding:: @end menu @node Setting the mark and hide bits @section Setting the mark and hide bits Every record may be thought of as having a pair of bits or boolean values indicating whether it is marked and whether it is hidden. The most straightforward way to set these bits is to use an operation to mark, unmark, hide, or unhide a particular record; these are bound to keystrokes in Database View mode. @table @kbd @item m @deffn {Command} db-mark-record Toggle whether the current record is marked. With a nonzero prefix argument, set it to be marked. With a zero prefix argument, set it to be unmarked. @end deffn @item O @deffn {Command} db-hide-record Change whether the current record is hidden. With a nonzero prefix argument, set it to be hidden. With a zero prefix argument, set it to be unhidden. @end deffn @end table The searching commands, when called with a prefix argument, mark each matching record (@pxref{Searching}). Once all records of interest have been marked, through one or more marking and/or searching commands, unmarked records can be hidden from consideration. This is useful if you want to work on only a small number of records, or if specifying the records of interest is easier than specifying those not of interest: instead of hiding all the uninteresting records, simply mark the interesting ones, then use the following command to cause the unmarked ones to become hidden. @deffn {Command} db-hide-unmarked-records Enable hiding, hide all unmarked records, and clear all mark bits. @end deffn The converse operation transfers information from the hide bits to the mark bits. @deffn {Command} db-mark-unhidden-records Mark all unhidden records. Also clears all hide bits. @end deffn It is also possible to clear all the mark or hide bits. @deffn {Command} db-unmark-all Clear the mark bit of every record. @end deffn @deffn {Command} db-unhide-all Clear the hide bit of every record. @end deffn Generally, to set or clear either the mark or hide bits of an arbitrary record of a database, you need to obtain the appropriate @dfn{tag} with @code{edb-tag}, passing it and the record to one of the functions described below. @defun edb-tag name db Return the tag object named @var{name} associated with database @var{db}. For EDB 1.x, @var{name} can be one of the keywords: @code{:markedp} or @code{:hiddenp}. The tag object can be passed to @code{edb-tagp}, @code{edb-tagx} and @code{edb-tag-}. @end defun @defun edb-tagp tag record Return t if @var{record} has its @var{tag} set. @end defun @defun edb-tagx tag record Set @var{tag} for @var{record}. @end defun @defun edb-tag- tag record Clear @var{tag} for @var{record}. @end defun For example, this function sets the mark bit on those records (@pxref{Mapping over the database}) for which @var{predicate} returns non-nil: @lisp (defun my-mark-if (predicate) (let ((mtag (edb-tag :markedp dbc-database))) (db-maprecords (lambda (record) (when (funcall predicate record) (edb-tagx mtag record)))))) @end lisp @node Movement among marked and hidden records @section Movement among marked and hidden records Ordinarily, record movement commands (those which move from one record to another) ignore hidden records, so that you never land on a hidden record. Marked records, on the other hand, are not treated specially by the record movement commands. The following Database View mode keystrokes permit you to move to hidden records or to move directly to marked records. @table @kbd @item M-n @deffn {Command} db-next-record-ignore-hiding [arg] Go to the @var{arg}th next record, ignoring omissions. That is, all records, even those which are hidden, are counted. @end deffn @item M-p @deffn {Command} db-previous-record-ignore-hiding [arg] Go to the @var{arg}th previous record, ignoring omissions. That is, all records, even those which are hidden, are counted. @end deffn @item M-C-n @deffn {Command} db-next-marked-record [arg] Go to the @var{arg}th next marked record. Hidden records are treated according to db-hide-p. @end deffn @item M-C-p @deffn {Command} db-previous-marked-record [arg] Go to the @var{arg}th previous marked record. Hidden records are treated according to db-hide-p. @end deffn @end table @node Details of hiding @section Details of hiding The @dfn{hidden} bit of each record has no effect unless @dfn{hiding is in effect}. When hiding is not in effect, the values of records' hide bits are remembered, and they may still be set and unset, but they have no effect on any operations until hiding is once again in effect. Enabling hiding makes @samp{Hide} appear in the mode line of the database buffer. The following operations work in either Database View mode or Database Summary mode. @table @kbd @item M-o @deffn {Command} db-hiding-toggle [arg] Change whether hiding is in effect. With a nonzero prefix argument, turn hiding on. With a zero prefix argument, turn hiding off. This does not change the current hide-function, and a hide bit is always computed for each record, but hide bits have no effect on any operations if hiding is not in effect. @end deffn @item M-C-o @deffn {Command} db-toggle-show-hidden-records [arg] Toggle whether hidden records are shown in the summary. With a nonzero prefix argument, show hidden records in the summary. With a zero prefix argument, don't show hidden records in the summary. @end deffn @item M-O @deffn {Command} db-hiding-set Set the criteria for automatically determining whether to hide a record. This isn't implemented yet. @end deffn @end table @node Reports @chapter Reports @cindex reports Reports can be generated from a database by using the following command in view mode: @table @kbd @item r @deffn {Command} db-report [report-filename [markedp]] Create a report according to @var{report-filename}. Prefix argument @var{markedp}, if non-@code{nil}, means report on only marked records. If hiding is in effect, hidden records are not reported upon. When called interactively, prompts for @var{report-filename}. @end deffn @end table The way a report looks is specified in precisely the same as are display formats and summary formats (@pxref{How information is displayed}). This information must be placed in a file; you cannot type it directly when creating a report. This restriction makes errors in the report format easier to correct. The report is placed in the @samp{*Database Report*} buffer, which is in Text mode. The information may then be edited, saved to disk, or otherwise manipulated. The buffer is in Text mode and is not yet a file; you must save it to make it a file. To create a report which mentions only marked records (@pxref{Marking and hiding}), supply a prefix argument to the report command by typing @kbd{C-u} first. @node Specifying the display format @chapter Specifying the display format @cindex display format, selecting Different layouts and on-screen arrangements of the values stored in database records are appropriate when you are concentrating on different aspects of the data. Sometimes you prefer to see just a few of the fields; at other times you may want to see the records in full detail. It may also be appropriate for the display format of a record to depend on the record's field values. This section describes how to choose a different display format for the record being displayed, either manually or automatically. @menu * Changing display formats:: * Execution of format file eval expressions:: * Making additional data display buffers:: @end menu @node Changing display formats @section Changing display formats @cindex changing display formats @cindex alternate display formats @cindex variant display formats @cindex display format, alternate @cindex display format, variant EDB permits the creation and use of a variety of display formats with a single database; you can also conveniently change the way that a particular record is displayed by using @code{db-change-format} and specifying the filename of the new display format, or a nickname for the format that has been assigned either during the session or before-hand. Choosing a different format does not create a new data display buffer; it changes the way that records are displayed in the current one. @deffn {Command} db-change-format [format-name [filename]] Select and use an alternate display format to view the database. If neither @var{format-name} nor @var{filename} is specified (as is the case when this is called interactively), then prompt for them. In Emacs Lisp code, if @code{dbf-format-name-spec-alist} has been been set, usually only one of the arguments is specified. If both are specified, then @var{format-name} becomes a name for the format @var{filename} specifies; if @var{format-name} is already associated with a different format file, an error is signalled. If the current format is unnamed, then prompt for a name to give it, so that it can be conveniently restored if need be. This behavior is suppressed, and the record is not displayed, if the function is not being called interactively. The data display buffer is left in Database View mode. Selecting the current format does not cause any work to be done. Some databases automatically set the format of the record being displayed, usually by setting @code{dbf-before-display-record-function} to a function that overrides the format in effect when a record is about to be displayed. This may cause this function to appear not to be doing any work. In actuality the format is being set, then reset. @end deffn @cindex format-spec structure @cindex specifier, format @defvar dbf-format-name-spec-alist Association list of format names and format specifiers. Each format name is an arbitrary string. A format specifier is a filename or format file specifier, which is a list of values for format variables. When the format specifier is a filename, after that format file has been read, EDB replaces the filename with a list of values for format variables, so that the file need not be read again. This variable is set automatically for each @code{:display} control property specified (@pxref{Control properties reference}). If there is only one @code{:display} and it is without a name, its name is taken as @file{t}. @end defvar These values can be set in the auxiliary or format files so that you can choose a format name (with completion) instead of having to remember a filename. If the selected format's specifier is a filename, then after the file is read in, the format-spec is modified by replacing the filename with information about the format such as the displayspecs, the invariant text between them, and so forth. Subsequent selections of that format do not cause disk accesses. For an example of the use of @code{db-change-format}, @xref{Record display hooks}. @cindex hiding fields from a data display buffer @cindex data display buffer, hiding fields While it is not currently possible to selectively hide certain fields from a data display buffer, judicious use of alternate formats can result in nearly the same effect. @node Execution of format file eval expressions @section Execution of format file eval expressions @cindex local variables section of format file @cindex format file, local variables section @cindex format file, eval expressions in @cindex eval expressions, in format file @cindex primary format file @cindex format file, primary Often the local variables section of a format file contains code that should only be executed once, or should only be executed before the database is read in, because of either efficiency or correctness constraints. Because of this, the local variables section of a format file is executed only when it is read in from disk (which is usually only once). In order to cause an expression to be evaluated every time that a particular display format is selected, use the @code{dbf-always} macro: @defmac dbf-always [body...] Execute forms in @var{body}, and arrange to execute them in the future each time that this format replaces another. @end defmac Of course, it is often valuable to overwrite a value when the display format changes; this is the purpose of @code{dbf-always}. It is always safe to set variables whose name begins with @code{dbf} in such forms, though changes to some such values will not take effect when a display format is being returned to (though they will work when it is first chosen). This will affect you only in that a call to @code{dbf-set-summary-format} will have an effect only the first time that a format file is read in, not every time that it replaces another, even if it is enclosed in a @code{dbf-always} form. The @code{dbf-always} forms are not executed every time that a record is displayed, or even every time that @code{db-change-format} is called, but only when a format replaces another one (that is, @code{db-change-format} is called and its first argument is not equal to the name of the current format). Here is an example of a common problem with an expression which causes an error if evaluated every time that the format is selected. The primary format file (the one that is used when the database is read in) is permitted to define the fields (names and types) of the database; other parts of the database initialization code propagate that information into other parts of EDB, caching and transforming things in the process. If you switch to another display format and back to the primary one, and the the field names have been re-initialized to their original forms again, then the next attempt to access this information (expecting a pre-transformed object) would cause an error. In this case, the proper solution is to use @code{database-set-fieldnames-to-list} (@pxref{Specifying a record field type}) instead, but such functions are not provided for every slot that it would be dangerous to set. If several format files all set a value which is dangerous to change, then another possibility is to check the value before setting it: if it is already set, then don't do anything. Another possibility is to move all assignments to database slot values from the format file to the auxiliary file. @node Making additional data display buffers @section Making additional data display buffers @cindex additional data display buffers, making @cindex data display buffers, making additional @cindex two records, manipulating simultaneously @cindex simultaneously manipulating two records @cindex two formats, using simultaneously @cindex simultaneously using two formats In addition to changing the display format of an existing data display buffer, it is sometimes useful to have two different data display buffers both examining the same database, either so that two different records can be viewed or edited simultaneously or so that two different formats can be used at the same time --- or both. Use the following function (normally bound to @kbd{+} in Database View mode) to create a second (or additional) data display buffer for the current database. @deffn {Command} db-additional-data-display-buffer Create another data display buffer in which to view this database. @end deffn If you edit the same record in more than one data display buffer, only the last one committed (by calling @code{db-accept-record}, moving to another record, saving the database, etc.)@: has an effect. (Simply switching from Database Edit mode to Database View mode does @emph{not} commit the changes; failing to commit changes makes it appear that changes in one data display buffer are not being communicated to the other ones associated with the same database. For more on committing, @xref{Making changes permanent}.) It is perfectly safe, however, to edit different records of the same database in different data display buffers, or to perform any other database manipulations. To learn about formatting directives and specification of display format files, @xref{How information is displayed}. @node Specifying control @chapter Specifying control @cindex specifying control @cindex control properties The control for a particular data source comprises several different types of specification, describing all aspects of the data with respect to a connection session: its shape in abstract, its internal relationships, its representation outside of Emacs, its representation in an Emacs buffer, and various other meta-data. These are collectively known as the @dfn{control properties}, most of which must be specified in the process of making a connection, by grouping them into a control file (or buffer) that begins with the magic text: @example :EDB (single BASIS) ;;; -*- emacs-lisp -*- @end example Actually, the @kbd{;;; -*- emacs-lisp -*-} is optional; it is sufficient that on the first non-comment, non-blank line, the first four characters are colon and @kbd{EDB}, followed by a space followed by a list whose first element is the name of a supported @dfn{schema-schema}. At the moment (for EDB 1.x), the unique available schema-schema, and the subject of the rest of this manual, is @code{single}. Also, not all control can yet be specified with control properties; some ``normal'' Emacs Lisp variables and functions are still required. @xref{Ongoing migration}. @var{basis} is an optional variable name (symbol) whose value specifies in property list form a set of control properties that are to be used as the basis --- i.e, elaborated (@pxref{Interpreting control properties}) first --- for those specified in the rest of the buffer. This is useful for collecting in one place properties that are shared by many databases. @menu * Interpreting control properties:: * Kinds of control property values:: * Control properties reference:: * New control example:: * Ongoing migration:: * Changing control properties at runtime:: * Example control file from scratch:: @end menu @node Interpreting control properties @section Interpreting control properties @cindex interpreting control properties @cindex control properties, interpretation The way EDB processes a control file is designed so that you can express control properties primarily declaratively, while still permitting arbitrary computation, all in one place. Besides the magic header (@pxref{Specifying control}), the rest of the control file contains, at the top-level, a mix of free-standing Lisp, and alternating control property names (keywords) and their associated @dfn{values-producing forms}. Unlike @code{load} (or @code{load-file}), which can be described as a straightforward read-eval loop, control file processing is a bit more complicated. Specifically, EDB: @enumerate @item Checks the magic. @item Parses the buffer using @code{read} and some helper funcs, accumulating the free-standing Lisp separately from the control properties. The helper funcs transform the text blocks associated with certain control properties into a plist. For example, given a buffer fragment: @example :display t first second :EOTB @end example @noindent Then parsing yields the form (associated with @code{:display}): @lisp (:name t :coding t :EOTB "EOTB" :text "first\nsecond\n") @end lisp @item Evaluates, in order, the free-standing Lisp. @item Validates the syntax of the control properties. @item ``Elaborates'' the form associated with each control property, to get the actual control property values, and superficially checks these values. The elaboration method depends on the form: @itemize @item A list whose @sc{car} is a string is used directly. @item A list whose @sc{car} is a keyword is used directly. @item For all other cases, @code{eval} the form. @end itemize This allows (certain) control property values to be computed at connection time. For example, here are two equivalent ways to set the @code{:fields} control property: @example ;;; first way: literal :fields [time place] ;;; second way: computed :fields (vector 'time 'place) @end example Here is another example which shows four functionally-equivalent ways to set the @code{:write-record} control property: @example ;;; first way: external function (require 'my-edb-setup) :write-record 'my-write-record ;;; second way: defun (defun my-write-record (time place) ...) :write-record 'my-write-record ;;; third way: defun integrated into decl :write-record (defun my-write-record (time place) ...) ;;; fourth way: lambda (the ultimate) :write-record (lambda (time place) ...) @end example Although the ways are functionally equivalent, each has its consequences. The first way allows you to use a byte-compiled function (presuming it is defined in @file{my-edb-setup.el} and you byte-compile that file). Furthermore, once @file{my-edb-setup.el} provides (or arranges to provide) feature @code{my-edb-setup}, it is no longer loaded on subsequent connections. Contrast this with the second and third way, which redefine @code{my-write-record} on every connection. The first three ways allow a breakpoint to be set (using @code{edebug}, for example) on the function. The fourth way avoids burdening the already-crowded Emacs namespace by making use of an anonymous function. @item Saves the control properties (how and where presently not described in this manual, but maybe in the future...). @end enumerate @node Kinds of control property values @section Kinds of control property values @cindex kinds, control property values @cindex characteristics, control property values This section describes some characteristics common to the values of certain control properties. (We resist using the term ``type'' here because that term is extremely overloaded in EDB, Emacs, and indeed throughout all of computer science and programming.) @macro cpropvaltype{name} @item @cindex \name\ (type) @end macro @itemize @cpropvaltype function whose arglist specifies field names Some properties (for instance, @code{:write-record}) specify a function whose @dfn{arglist specifies field names}. That is, the values of the specified fields of the current record are bound to function parameters with the same name. @cpropvaltype text-block specification Some properties (for instance, @code{:display}) specify a @dfn{text-block specification}, which is either a plist that specifies how to further process inline data, or @code{t} which expands to the default spec. Properties of the plist are: @code{:EOTB}, a string (default ``:EOTB'') that delimits the text block when appearing on a line by itself; @code{:name}, a string that names this text block, or @code{t} (default); @code{:coding}, a symbol that specifies the coding to use when reading the text block, or @code{t} (default) which means use the current buffer's coding. [EXPERIMENTAL / DO NOT RELY ON THIS: Additionally, for control property @code{:data}, the text-block spec must include @code{:seqr}, a symbol naming a function defined in the @code{single} schema-schema.] Here is an example showing two @code{:display} specifications, both named, and the latter using @samp{foo} as the end-of-text-block indicator: @example :display (:name "time first") At \time\ , we need to be at \place\ . :EOTB :display (:name "place first" :EOTB "foo") Let's try to be at \place at \time\ , for once! foo @end example @cpropvaltype string or regexp vector Some properties specify a @dfn{string or regexp vector}. This means the value is either a string, or a vector of either two or three elements, whose first element is a regular expression (string) and whose second element is an integer specifying the relevant submatch number (use 0 to mean that the text matched by the entire regexp is relevant). If the vector has three elements, the third element is a string used when writing. To maintain format integrity (to be able to read back what is written), this string should match the regexp specified in the first element. In other words: @lisp (let ((v [REGEXP SUBMATCH WRITE-STRING])) (string-match (aref v 0) (aref v 2))) @end lisp should have a non-nil value. Be careful! (At this time, EDB does not check this relationship; you have to check it yourself. Omitting or specifying the wrong @var{write-string} silently corrupts the data during write. This laxity ostensibly supports read-only interaction...) @cpropvaltype record initializer function Some properties specify a function that must @dfn{return a record initializer}. This means the return value is either a plist of alternating field names (symbols) and values, or a list whose @sc{car} is the keyword @code{:alist}, followed by an alist associating field names and their values. @end itemize @unmacro cpropvaltype @node Control properties reference @section Control properties reference @cindex control properties reference This section describes all the control properties recognized in the @code{single} schema-schema, grouped according to typical usage. @xref{Kinds of control property values}, for information on common characteristics. @macro cprop{name,rest} @item \name\ \rest\ @vindex \name\ control property @end macro @subsection Minimal required Most control properties are optional; however, a minimal control requires @code{:display} and either @code{:fields} or @code{:tagged-setup}. @table @code @cprop{:display, TEXT-BLOCK-SPEC} This control property is required. @xref{Display specifications}. There may be more than one @code{:display} control property, in which case the respective @var{text-block-spec} should include @code{:name STRING}, and you should specify @code{:choose-display} to select one of the formats. @cprop{:fields, VECTOR} Each @var{vector} element is either a field name or a cons whose @sc{car} is a field name and whose @sc{cdr} is a type name (both symbols). Either @code{:fields} or @code{:tagged-setup} must be specified, but not both. @xref{Record field types}. @cprop{:tagged-setup, PLIST} @var{plist} must include @code{:fields (TAGGEDFIELDSPEC ...)}, where each @var{taggedfieldspec} has the form @code{(FIELDSPEC TAG DESCRIPTION)}. @var{fieldspec} can be either a field name, or a cons whose @sc{car} is a field name and whose @sc{cdr} is a type name. @var{tag} and @var{description} are both strings. @xref{Tagged file layout}. Either @code{:fields} or @code{:tagged-setup} must be specified, but not both. @xref{Record field types}. @end table @subsection File layout Several control properties pertain to I/O, i.e., reading and writing to an external data source/sink. Note that some of these override others. @xref{Database file layout}. @table @code @cprop{:read-record, FUNCTION} @var{function} is repeatedly called with no args to parse the accessible (narrowed) region of the data file, to return a record initializer for the data represented in that region. When called, point is at each region's point-min. If specified, control property @code{:field-separator} is ignored, since @var{function} does all the parsing work. @cprop{:write-record, FUNCTION} @var{function}, whose arglist specifies field names, is called to insert into the current buffer at point the external representation of the current record's data. The arglist may also be nil, in which case all field values are dynamically bound to variables with the same names as the fields. @cprop{:record-separator-function, FUNCTION} @var{function} takes a buffer position, the end of the previous separator (that is, the start of the current record or field), and returns a pair of two buffer positions bracketing the next separator. That is, the returned values are the end of the current record or field and the beginning of the next one (or nil if there are no more). When @var{function} is called, point is at the beginning of an item and the buffer is narrowed to the region being currently processed. If specified, @code{:record-separator} and @code{:record-terminator} are ignored. @cprop{:record-terminator, STRING-OR-REGEXP-VECTOR} If specified, takes the place of (overrides) @code{:record-separator} and additionally specifies that @var{string-or-regexp-vector} appears after the last record, as well as between records. @cprop{:record-separator, STRING-OR-REGEXP-VECTOR} The default is the string consisting of one newline (ASCII 0xA) character. @cprop{:field-separator, STRING-OR-REGEXP-VECTOR} The default is the string consisting of one tab (ASCII 0x9) character. @cprop{:substitution-separators, [FSEP RSEP]} A special case of @code{:substitutions} (below), @var{fsep} and @var{rsep} (both either a string or nil) specify what to write to disk in place of the regular field and record separators, respectively, in the case where those separators are found in the data itself. If unspecified, values are automatically chosen. (How?) @cprop{:substitutions, VECTOR} Each element in @var{vector} is a cons of two strings, specifying substitutions on the data to be made on read (beginning to end, s/car/cdr/) and write (end to beginning, s/cdr/car/) operations. Note: use @code{:substitution-separators} to disambiguate field and record separators instead of this control property. @cprop{:cruft, [[BEFREC AFTREC] [BEFFLD AFTFLD]]} This is a catch-all for specifying irregular file formats. The value is a vector of two elements, each in turn a vector of two elements. Each of @var{befrec} (before record), @var{aftrec} (after record), @var{beffld} (before field) and @var{aftfld} (after field) is a string or regexp vector. @cprop{:data, TEXT-BLOCK-SPEC} This is an EXPERIMENTAL control property that specifies that the data is inherent in the control (specifically, in the text block following this control property) instead of residing elsewhere. To ``save'' inherent data, EDB updates the text block and, if the control is associated with a file on disk, saves the control to disk. A control with inherent data can be useful for read-only and/or dynamically generated data sets. At present, inherent data usage is extremely stylized: @itemize @item @var{text-block-spec} must include @code{:seqr read-line}, and the text block must consist of one vector, representing a record, per line. EDB does not validate the record for well-formedness. @item @var{text-block-spec} should include @code{:seqw write-line}, if the data is to be saveable. (You may omit this if you plan to use the data in a read-only manner.) @item If the control is not visiting a file, it must not be deleted for the lifetime of the data access. If the control is a file-visiting buffer, on the other hand, you can delete it without harm, once EDB is done processing it and has set up a data display buffer. In either case, you should take care to not modify the control while its data is under EDB's care, for that would probably confuse EDB when it tries to update the text block. Result: not only data corruption (bad), but control corruption (very bad), as well. @end itemize @end table @subsection Display Some control properties affect what you see in an Emacs buffer. @xref{How information is displayed}, and @code{:display} (above). @table @code @cprop{:choose-display, FUNCTION} @var{function}, whose arglist specifies field names, is called immediately prior to display a record in the data display buffer. It should return a string naming one of the display formats defined with @code{:display}. This function overrides that of @code{:before-display}. @cprop{:before-display, FUNCTION} @var{function}, whose arglist specifies field names, is called immediately prior to displaying a record in the data display buffer. This control property is ignored if @code{:choose-display} (above) is specified. @cprop{:report, TEXT-BLOCK-SPEC} This specifies a report template. @xref{Reports}. @cprop{:summary-format, STRING} @var{string} is a concise (preferably one line) template for the summary buffer. @xref{Database Summary mode}. @end table @subsection Miscellaneous @table @code @cprop{:name, STRING} @var{string} is used for informational purposes (messages and prompts). If unspecified, EDB assigns the default ``Unnamed Database N'', where @var{n} is some positive integer. @cprop{:first-change-function, FUNCTION} @var{function} is called the first time a field changes value (due to editing) with three args: the field name (a symbol), the old value, and the new value. @cprop{:every-change-function, FUNCTION} @var{function} is called every time a field changes value (due to editing) with three args: the field name (a symbol), the old value, and the new value. @cprop{:field-order, VECTOR} @var{vector} specifies the priority of significant fields for a sort operation (elements towards the beginning have precedence over those towards the end). Each element is either a field name or a cons whose @sc{car} is a field name and whose @sc{cdr} is a symbol: @code{ascending} or @code{descending}, which specifies that the field is to be sorted in ascending or descending order, respectively; or a cons of @var{type} and @var{value}, where @var{type} is a symbol (either @code{order-function} or @code{sort-function}) and @var{value} specifies the function. If unspecified, the default field order is taken to be the same as in @code{:fields}, i.e., all fields significant and sorted in ascending order. @xref{Sorting}. @cprop{:locals, VECTOR} Each element of @var{vector} is either a symbol, or a list of the form @code{(@var{symbol} @var{init-form})} --- like an entry in a @code{let}-bindings block. These define variables (mostly opaque to EDB) unique to the connection. The associated value is the value of evaluating @var{init-form} (if the element is a cons), otherwise nil. @cprop{:record-defaults, FUNCTION} @var{function} is called with no args when first adding a record, to return a record initializer. @end table @unmacro cprop @node New control example @section New control example @cindex new control example @cindex example, new control This section describes a simple example database and the steps required to construct an appropriate control buffer to connect to it. First, we must decide how many fields the database shall contain, and their names and types. The names are Lisp symbols, and cannot be either @code{t} or @code{nil} for implementation reasons (those symbols cannot be used as variable names in Emacs Lisp). Let us make a name database with three string fields called @samp{first}, @samp{middle}, and @samp{last} and one integer field called @samp{age}. Next, we must decide how a record is to be displayed in an Emacs buffer. Let us try the following: @example Family: \last Given: \first Middle: \middle Age: \age @end example The backslash followed by a field name indicates that the field's contents should be inserted there. For more information about specifying display formats, @xref{How information is displayed}. Lastly, we need to compose a control buffer comprising a standard header, and the two pieces of information we've decided upon. So we type: @itemize @item @kbd{C-x b my-names.edb @key{RET}} @item @kbd{M-x emacs-lisp-mode @key{RET}} @end itemize @noindent and insert the following (without the indentation): @example :EDB (single) ;;; -*- emacs-lisp -*- :fields [first middle last (age . integer)] :display t Family: \last Given: \first Middle: \middle Age: \age @end example (Alternatively, we can insert the file @file{names.edb} from the EDB distribution's @file{examples} subdirectory, or simply visit it.) Now we can type @code{M-x edb-interact @key{RET}} in this buffer, typing @key{RET} to specify this buffer as the control, and @file{my-names.data} (or any other non-existent filename) to specify the data. An ``empty'' record will be shown, ready to be filled in. @xref{Database mode}. (Alternatively, we can specify the file @file{names.dat} from the EDB distribution's @file{examples} subdirectory, in which case the record for Harry S. Truman (age 88) will be shown.) When we write out the data, fields and records will be separated by tab and newline, respectively. These are the default delimiters. For more information about customizing EDB for your application, @pxref{Customization}. Once we are happy with the control buffer, we can save it in a file for later use; we can then specify that file as the control for a subsequent @code{edb-interact} session. @node Ongoing migration @section Ongoing migration @cindex ongoing migration @cindex control without control properties Although most control can be declaratively specified, there are still some noticible holes (@pxref{Control properties reference}), which we will endeavor to close as we proceed towards EDB 2.x. Notably, to extend the recognized types requires calling functions. @xref{Specifying a record field type}, for record field types. @xref{Defining new displaytypes}, for display types. Also, several variables (that are not set automatically when some control property is specified) are available for tweaking with @code{setq} and/or @code{add-hook}: @table @code @item db-before-read-hooks @itemx db-after-read-hooks @xref{Read hooks}. @end table @node Changing control properties at runtime @section Changing control properties at runtime You can use @code{edb-get} and @code{edb-put} to access and modify, respectively, the value of certain control properties at runtime (and only at runtime, presently). @defun edb-get property &optional buffer Return the value associated with @var{property} for the current buffer. Optional second arg @var{buffer} specifies another one to use as ``current''. @end defun @defun edb-put property newvalue &optional buffer Set @var{property} to have @var{newvalue} for the current buffer. Optional third arg @var{buffer} specifies another one to use as ``current''. @end defun The following table describes the available control properties. The default value is the one used when setting up the buffer. @table @asis @item @code{:wraparound} (default: @code{delay}) This controls motion between the first and last record (and vice versa), when moving sequentially between records. A value of @code{nil} means do not wrap around; stop at the first or last record and display a message to that effect. A value of @code{delay} (a symbol) means to stop at the border, displaying a message, but wrap on the next attempt to move, anyway. A value of @code{t} means to wrap without stopping, and without displaying a message. @item @code{:stay-in-edit-mode-p} (default: @code{t}) A non-@code{nil} value means that when editing a record, moving to the next record stays in Edit mode. @end table @node Example control file from scratch @section Example control file from scratch @cindex WWW Links control file examples @cindex control file examples This section describes three example databases of increasing complexity and their associated control files. The data is a set of ``WWW Links''. We start with just the URL and add fields/features as we go along. All files are available in the distribution's @file{examples} subdirectory. @subsection WWW Links @dfn{WWW Link} is a fancy way to say ``URL''. The simplest database is just a list of these in a file, one per line. For example: @example http://www.gnu.org/ http://www.gnu.org/software/ http://www.gnu.org/software/emacs/ http://www.gnuvola.org/ http://www.gnuvola.org/software/ http://www.gnuvola.org/software/edb/ @end example It's easy to construct a minimal @file{www-links.edb} to grok this (note that (parenthesized) line numbers are for discussion, and should not appear in the actual working file): @example :EDB (single) (1) :name "WWW Links" (2) :fields [url] (3) :display t (4) \url (5) :EOTB (6) @end example Line 1 is boilerplate and will be assumed henceforth. Line 2 names the database. Line 3 declares that each record is composed of one field, whose name is @code{url}. The field type's is taken (implicitly) as @code{string}. Lines 4 through 6 describe the per-record display. The @code{\url} in that text block means to display the field @code{url} at that position. That's it! Use @kbd{M-x edb-interact RET examples/www-links.edb RET RET} to try it out. (The last @kbd{RET} is to let EDB find the data file, which is @file{examples/www-links} by default. You can, of course, specify another data file to use instead of the default.) @subsection WWW Links (Titled) In this subsection we extend the simple database introduced in the previous subsection to add a @code{title} field. Since the line-oriented (one record per line) approach is pleasant enough, the only design decision we have to make is how to separate the fields in each record, and their order. Although @code{TAB} (aka @code{^I} aka @code{C-i} aka ``control i'') is the traditional (and thus default) field separator, that might cause problems if that character were to appear in the title. We choose @code{^T} instead, since it is virtually guaranteed not to conflict, and ``T'' is a workable mnemonic for ``title'' (bonus!). As for the order of fields in the data file, let's keep the URL first since it is most important. (Although a title without a URL might be useful as a placeholder, our goal is to organize ``links'', which implies a certain connectedness requirement.) To effect this new design in a new data file, we can evaluate the form: @example (with-temp-file "www-links2" (insert-file-contents "www-links") (while (< (point) (point-max)) (end-of-line) (insert "\C-t") (forward-char 1))) @end example Next we copy @file{www-links.edb} to @file{www-links2.edb} and make the following modifications: @example :name "WWW Links (Titled)" (1) :fields [url title] (2) :field-separator "\C-t" (3) :display t (4) \title (5) \url (6) :EOTB (7) @end example Line 1 updates the title. Line 2 declares the ordering in the data file and names the second field @code{title}, with type (implicitly) @code{string} as for @code{url}. Line 3 declares the field separator. Lines 4 through 7 describe the per-record display. Note that in the display we place the title first and on a line by itself. This has implications in the summary (@pxref{Database Summary mode}), which defaults to the first line in the @code{:display} text block with a displayspec in it. With these changes, we can @code{edb-interact} with @file{www-links2.edb} and: type @kbd{e} once to enter edit mode; type in a title; use @kbd{M-n} and @kbd{M-p} to move to next/previous records, staying in the @code{title} field; type @kbd{C-x C-s} to save and @kbd{x} to exit. @subsection WWW Links (Everything) In this subsection, we further extend the database to include two fields: @itemize @item date when the URL was last checked for reachability; @item comments (notes, critiques, etc) @end itemize For the date, we use a custom data type @code{suredate}, defined as: @example (edb-define-recordfieldtype 'suredate 'date :actual->stored 'edb-t-timedate1:format-date-iso :stored->actual 'edb-t-timedate1:parse-date-string) @end example Comments are just another string, but there is a catch: we would like to support multi-line comments, such as: @example This site is ok, but I wouldn't want to have to maintain it, for these reasons: - probably doesn't use EDB for its database - requires javascript, which w3m doesn't do @end example The implication is that we can no longer use one record per line, as some records may contain the newline character in the @code{comments} field. So, let's choose formfeed (aka @code{^L} aka @code{C-l} aka ``control l''). To effect this new design in a new data file, we can evaluate the form: @example (with-temp-file "www-links3" (insert-file-contents "www-links2") (while (< (point) (point-max)) (end-of-line) (insert "\C-t\C-t\C-l") (if (= (point) (point-max)) (delete-char -1) (forward-char 1)))) @end example Next, we create @code{www-links3.edb}, modifying the control property @code{:name}, as usual, and adding @code{edb-define-recordfieldtype} as described above. The rest of the file looks like: @example :fields [url title (last-check . suredate) comments] :record-separator "\C-l" :field-separator "\C-t" :display t \title \url (\last-check,date-iso) Comments: \comments :EOTB :summary-format "\\last-check,width=11 \\title" @end example Note that the @code{last-check} field is declared with type @code{suredate} in @code{:fields}, is displayed with the @code{date-iso} format in the @code{:display} text block; and is explicitly included (with maximum width of 11 columns) in @code{:summary-format} (the double backslashes are required because the value is an Emacs Lisp string). @node Record field types @chapter Record field types @cindex record field type @cindex field type, record @cindex type, record field All the records of a database contain fields of the same types: the fifth field might always contain an invoice number, for instance, but the invoice number would vary from record to record. This chapter describes how to specify and use different record field types. The most important information about a record field is @itemize @bullet @item display representation onscreen and in reports @item EDB's internal representation @item storage representation in data files @item how to convert among these representations @item how to sort items of that type @end itemize @cindex record field type, compared to displaytype @cindex displaytype, compared to record field type This information is separated into a display specification and a record field specification. The display specification determines how a field's contents are displayed and parsed onscreen (say, in a data display buffer). The record field specification controls everything else about the record field; its information does not depend on the onscreen (or in-report) visual appearance of the field. The control specifies a displaytype for each display specification in the format file (that is, for each location in the data display buffer that will contain a representation of some record field), and specifies a record field type for each field in a database record, whether or not the field is ever displayed. (A particular field's contents may appear zero, one, or more times in a data display buffer; one displayspec structure is created for each occurrence.) Displaytypes and record field types are distinct; they supply complementary information. There is not even a one-to-one relation between them. A particular record field type may be displayed in any of a number of ways by using different displaytypes --- dates are such an example. On the other hand, record field types which are interpreted, sorted, and stored on disk differently, but which have the same internal representation --- say, as a string --- could all be displayed and edited using the same displaytype. This chapter discusses record field types, record field specifications, and lists the attributes upon which the other two are built. For more information about displaytypes, display specifications, and the displayspec structure, @pxref{How information is displayed}. @menu * Specifying a record field type:: * Predefined record field types:: * Record field attributes:: @end menu @node Specifying a record field type @section Specifying a record field type @cindex specifying a record field type @cindex record field type, specifying @cindex type, specifying record field The function @code{database-set-fieldnames-to-list} specifies the types (and names) of record fields. This function is called automatically when either of the control properties @code{:fields} or @code{:tagged-setup} is specified. @defun database-set-fieldnames-to-list database fspecs [dtype] Set @var{database}'s field names and record field types according to @var{fspecs}, canonicalizing and caching internally various things, but do nothing if the information has already been canonicalized. @var{fspecs} is a list, each element of which can either be a single symbol, the field name, or a cons @code{(NAME . RECORDFIELDTPYE)}. Optional third arg @var{dtype} specifies the default recordfieldtype for single-symbol elements. If @var{dtype} is not given, use the value of @code{db-default-field-type} if bound, or @code{string} otherwise. @end defun @vindex db-default-field-type Some notes on the deprecated variable @code{db-default-field-type}: There has been some confusion over usage of this variable; the ideas of ``default value'' and of ``buffer-local variable'' do not mix well together, especially when the value in this case is the recordfieldtype of the field, a property of the field and not of its display mechanism or of any buffer. Thus, if you have old code that sets this variable, you should change it to pass that value as the third argument to @code{database-set-fieldnames-to-list}. A record field type gives information about one field of the database's records: the type of the contents, what sorting function to use, how to write it to disk and read it back, constraints on its value, etc. Each record field has a record field type. Usually one of the predefined types suffices, but not always. You can use @code{edb-define-recordfieldtype} to create and install a new record field type. (The @code{-from-recordfieldspec} in the function name is a historical artifact; before being extended, the function used to only accept a recordfieldspec as @var{source}.) @defun edb-define-recordfieldtype name source [override...] Define a recordfieldtype @var{name} (a symbol) with @var{source}. @var{source} may be a recordfieldspec, the name (a symbol) of a currently defined type, or @code{nil}. In all cases, a new recordfieldspec object is created and then modified by @var{override}, a sequence of alternating keywords and values, and finally added to a global list. Return @var{name}. @end defun @xref{Predefined record field types}, for a list of symbols useful for the @var{source} argument. @xref{Record field attributes}, for a list of keywords useful as part of the @var{override} argument. After specifying the field names and types, it is usually a good idea to specify some field-specific help, as well. This kind of help is kept separate from the @code{:help-info} of each recordfieldtype (@pxref{Record field attributes}), since several different fields (requiring different help info) may specify the same recordfieldtype. @defun db-set-field-help database field1 help-info1 [...] Set field-specific help info for @var{database} from @var{field1} @var{help-info1}, @dots{}. @var{field1}, @var{field2}, @dots{} should be field names (symbols) or field numbers, while @var{help-info1}, @var{help-info2}, @dots{} should be either a string or a form to be evaluated that results in a string. @xref{Getting help}. This should be called after the field names have been set up. @end defun Examples of record field type creation and installation can be found in the file @file{db-types.el}, the source for most of the predefined types. Record field types should not be confused with display types; a display type is used to specify how a particular value is shown on the screen, but a record field type constrains the information actually contained in the record field. @node Predefined record field types @section Predefined record field types @cindex record field types, predefined @cindex predefined record field types The following record field types are predefined for your convenience; you can redefine them (they are not ``privileged'' in any way) or even add new record field types (@pxref{Specifying a record field type}). If you find any of these typenames cumbersome, you can create your own aliases for them using @code{edb-define-displaytype} or @code{edb-define-recordfieldtype}. @macro rftype{name} @item \name\ @cindex \name\ record field type @end macro @subsection Builtin These record field types are available as soon as EDB is loaded. @table @code @rftype integer Ordinary integers. @rftype integer-or-nil Integers or @code{nil}, the empty value; by default, @code{nil} is treated as larger than any integer, so it comes last in an increasing-order sort. @rftype number @cindex floating-point number record field type Ordinary numbers. A number is either an integer or a floating-point number. @rftype number-or-nil Numbers or @code{nil}, the empty value; by default, @code{nil} is treated as larger than any number, so it comes last in an increasing-order sort. @rftype boolean This displayspec corresponds to the yes-no displaytype. For the purposes of sorting, @code{t} is considered less than @code{nil}, so it appears first in an increasing-order sort. @rftype string Ordinary strings. @rftype one-line-string Strings which may not contain newlines. @rftype string-or-nil Either a string or the value @code{nil}, which is converted to the empty string. Sorting treats @code{nil} identically to the empty string. @rftype nil-or-string Identical to the string-or-nil record field type (except for the name). This exists so that display fields of type nil-or-string can conveniently default to this record field type. @rftype one-line-string-or-nil The obvious combination of the one-line-string and string-or-nil record field types. @end table @subsection From @file{edb-t-timedate1.el} Loading @file{edb-t-timedate1.el} provides some record field types related to the times and dates. The ``1'' is for upward-compatibility with a future time/date library variation that will make use of Emacs' intrinsic time/date support. (@file{edb-t-timedate1.el} was written a while back, before such support was added to Emacs, and may become unavailable once again in the future. See its Commentary section for more info.) @table @code @rftype date A date which specifies zero or more of the year, month, and day. By default the date is sorted by year, then month, then day; an unspecified component is larger than any specified component. For example, @code{March 14, 1967} would appear before @code{January 1} if dates were sorted in increasing order. Dates are read from database files using a function that can parse nearly any string representation of a date and return a date object if it is passed one. Dates are written using a function which produces a string of the form @code{March 14, 1967}. @rftype date-or-nil A date, or nil. @rftype date-efficient-storage @findex edb-t-timedate1:storage-string->date @findex edb-t-timedate1:simple-format-date When the dates in a database file are known to have a particular format, using @code{edb-t-timedate1:parse-date-string} is unnecessarily inefficient. The date-efficient-storage record field type specifies that @code{edb-t-timedate1:storage-string->date}, which can efficiently read dates written by @code{edb-t-timedate1:simple-format-date}, be used instead. The time savings is noticeable on large databases. @rftype time A time. @end table @unmacro rftype @node Record field attributes @section Record field attributes @cindex record field attributes @cindex fieldspec, see record field attributes Record field attributes pertain to the content of a record field, but do not address how it is displayed on the screen or read from interactive input. For that, @xref{How information is displayed}. Here is a table of valid attributes: @macro rfattr{name} @item \name\ @cindex @code{\name\} record field attribute @end macro @table @code @rfattr :type A symbol such as @code{string} or @code{integer}, the type of the data described by this collection of attributes. When no displaytype is explicitly specified in a display specification, then a displaytype with the same name as @code{:type} is used by default; this is the only use for this attribute. @rfattr :default-value The default value for fields described by this collection of attributes; used when creating new records. @rfattr :common-form-function A function which, called on the contents of a record field, returns them in canonical form. This can be used for determining non-trivial equality, when two nonidentical values should be considered equivalent. @rfattr :merge-function A function which, called on the contents of two record fields, returns a combination of the two. It may be interactive. @item :order-function @itemx :sort-function @cindex @code{:order-function} record field attribute @cindex @code{:sort-function} record field attribute @findex database-sort The record field's ordering and sorting functions (@pxref{Sorting functions}). Both ordering and sorting are possible if either attribute is specified. If both attributes are unspecified, then a dummy ordering or sorting function is used, so sorting on this field has no effect. Since the function is called and its result examined, this is more expensive than not sorting on the field in the first place. If it does not make sense to sort on a particular field, then it is best to keep that field out of the field priorities used for sorting (which is the @code{:field-order} control property, or is interactively specified through the database sort interface (@pxref{Sorting}), or is specified as an argument to @code{database-sort}). Actually, the record field type does not include order-function or sort-function information directly; they are built upon the value of the @code{:field-order} control property. @rfattr :match-function A function which takes a pattern and a field value and returns non-@code{nil} if they match. The function should also be able to take as its first argument a field value rather than a pattern. @rfattr :help-info A string which is displayed by @code{db-field-help} when there is no field-specific help available. Field-specific help is usually preferable to this help, which only describes the type of the field's contents. @rfattr :actual->stored A function which converts a field value into its on-disk representation (a string). @rfattr :stored->actual A function which recovers a field value from its on-disk representation (a string). If this function returns a string, it should return something reasonable if supplied the empty string as its argument. (That can happen when an empty database is read.) @rfattr :constraint-function @cindex enforcing constraints A function which the value of this field must satisfy; that is, the function must return non-@code{nil} on it. The function may reject the value either by returning @code{nil} or by signalling an error; the latter permits the function to provide an informative message about the problem. Four arguments are supplied to @code{:constraint-function}: the field value, the record, the record fieldnumber, and the database. This permits cross-field and cross-record constraints. The record argument may be @code{nil}, in which case the function should return @code{t} if the value is acceptable for some conceivable record. This occurs, for instance, when values are read in a call to @code{db-field-query-replace}. The constraint function may be interactive; for instance, it may give you the opportunity to override the constraint. @end table @unmacro rfattr @node Database file layout @chapter Database file layout @cindex file layout for data file @cindex file format for data file @cindex database file layout @cindex data file layout @cindex file layout @cindex layout, of data file @cindex format, of data file @c @cindex writing to disk @c @cindex saving to disk This chapter discusses specifying how a database is read from a file (or saved back to it). Broadly stated, there are three possible file representations for a database: EDB's internal file layout, a delimited layout, or a nonregular layout. EDB's internal file layout is designed for fast reading and writing, but is not very human-readable. A delimited layout is one in which records (and fields within a record) are separated from one another in a predictable (though not necessarily invariant) way. A nonregular layout is any other kind of layout; you may specify arbitrary Emacs Lisp code to read and write such files. EDB also supports tagged file layout (a special case of nonregular file layout). If the database is to be stored in EDB internal file layout, a lot of this information is not needed except when the database is first created. The sections of this chapter each describe a file layout, except the last, which describes in detail the process of reading a database from disk. @menu * Data encoding:: * Internal file layout:: * Delimited file layout:: * Tagged file layout:: * Relational file layout:: * Nonregular file layout:: * Reading from disk:: @end menu @node Data encoding @section Data encoding @cindex data encoding @cindex encoding, data @cindex coding system When connecting with @code{db-find-file}, the format file can specify that coding system to be used for the data by setting @code{edb-data-coding}. This variable is not meaningful when control is specifed using control properties. @defvar edb-data-coding A symbol in the Local Variables section of the format file specifying the coding system Emacs should use when reading and writing the data file. This coding system may be different from the one used for the format file. @end defvar @node Internal file layout @section Internal file layout @cindex file layout, internal @cindex data file layout, internal @cindex internal data file layout EDB 1.x supports an @dfn{internal file layout}, but EDB 2.x will not. This section details the layout, as well as how to migrate away from it (should you plan to move to EDB 2.x at some point in the future). @menu * Internal file layout details:: * edb-1int-to-single:: @end menu @node Internal file layout details @subsection Internal file layout details The first line of a database file in EDB's internal file layout looks something like @lisp ;; Database file written by EDB; format 0.7 @end lisp followed by two Emacs Lisp forms: a vector (the database structure), and an alist of various miscellaneous attributes. The rest of the file is a sequence of vectors (the records of the database). Databases stored in this layout can be read and written very quickly (sometimes orders of magnitude faster than databases which EDB must parse when reading), and they never suffer from ambiguities between data and delimiting text, but they are not easy for people to read and understand. A human- or program-readable version of the database can be generated when it is needed, either by creating a report or by saving in some other file layout. This is a good option when all manipulation of a database will be done via EDB. @cindex EDB internal layout, converting to or from @cindex converting a file to or from EDB internal layout Since this file layout is rather complicated, databases are often created in some other file layout and then converted to this one. To convert from another file layout to EDB's internal file layout, read in the database, use @code{db-toggle-internal-file-layout} to mark it for saving in that format, and then write or save the database (via @kbd{C-x C-w} or @kbd{C-x C-s}). @deffn {Command} db-toggle-internal-file-layout Toggle whether the database will be saved in EDB's internal file layout. With a nonzero prefix argument, set it to use internal file layout. With a zero prefix argument, set it not to use internal file layout. @end deffn After a database has been saved in internal file layout, then any forms in the auxiliary or format files that set database slots can be removed if desired; this is not necessary, however. Converting a database from EDB file layout to some other representation is similar, and certain variables and database values may need to be set (see the documentation for the layout you desire, elsewhere in this chapter). Making a report (@pxref{Reports}) can also produce a different file layout for a database, with even more flexibility than the techniques described here. @node edb-1int-to-single @subsection edb-1int-to-single EDB 2.x will not support internal file layout. Instead, it will have (and EDB 1.26 and later already have some) support for control with @dfn{inherent data} via the @code{:data} control property (@pxref{Control properties reference}). To ease migration, you can use @code{edb-1int-to-single} to do most of the tedious translation work, although you may need to help it a little. @macro FF @code{} @end macro @deffn Command edb-1int-to-single filename This command translates the contents of @var{filename} to a ``single'' schema-schema. If the contents are not in EDB 1.x ``internal file layout, format 0.7'', it signals an error. Otherwise, it leaves the result of the translation in a newly created output buffer named @kbd{:EDB (single) from FILENAME}. To compute the control properties written in the output buffer, @code{edb-1int-to-single} uses various (nefarious) methods to parse and repurpose the contents of two files: the one named by @var{filename}, as well well as the primary format file (if it can be determined --- see below). Additional format files and the auxiliary file, if any, are @emph{not} consulted. @end deffn The local variables block in the primary format file can have either @code{eval: FORM} pseudo-variables or @code{VAR: VAL} specifications. If an @code{:eval} form looks like a function call for one of these functions: @lisp database-set-fieldnames-to-list --- "redundant" comment dbf-set-summary-format --- translate to :summary-format @end lisp then @code{edb-1int-to-single} handles it specially (as indicated). An informative comment is also output to help keep track of things. If, on the other hand, the @code{eval:} form is not recognized, it is added to the output anyway, but commented out. Similarly, these variables (@code{VAR: VAL} in the local variables block) are handled specially: @lisp db-new-record-function dbf-first-change-function dbf-every-change-function dbf-before-display-record-function dbf-format-name-spec-alist edb-data-coding @end lisp (i.e., commented out), and all others translated into @code{:locals}. Here are all the control properties written. Those in the first column are always written, while those in the second are conditionally written. @example :name :field-priorities :fields :summary-format :display :substitution-separators :data :substitutions :locals @end example These short lists show that there are many control properties that @code{edb-1int-to-single} does not even attempt to infer. Indeed, even when it tries its best, the output buffer is likely to contain several @FF tokens, indicating places where further attention (a nice way to say ``manual tweaking'') is required to complete the translation. Following is a complete table of possible @FF occurances, with the reason for the @FF and the suggested remedies. Note that suggestions involving editing the output buffer by hand are not compatible with those involving iteratively tweaking something in the input file or environment and re-invoking @code{edb-1int-to-single}, since re-invocation clobbers hand-edits. Thus, a good strategy would be to do the upstream tweaking fixes first, saving the hand-editing fixes for last. @table @asis @item @code{coding:} in the first line This occurs when the variable @code{coding-system-for-read} is @code{nil} during the call to @code{edb-1int-to-single}. This is a relatively serious situation, as recent versions of GNU Emacs may refuse to save the file altogether since @FF does not name a valid coding system. One way to fix this is to replace the @FF with the appropriate coding system for the control file (i.e., resorting to editing by hand). Another way is to call @code{universal-coding-system-argument} (normally bound to @kbd{C-x @key{RET} c}) immediately prior to translation (via @kbd{M-x edb-1int-to-single}). Yet another way is to remove the @code{coding:;} completely, thus foisting the responsibility of specifying the file's coding system on another person (or mechanism) at another time. Note that you must remove the trailing semicolon as well. @item @code{:name} control property This occurs when the original name is @code{nil}, which should never happen according to internal EDB constraints (but you never know). To fix, choose a suitable description for the data (a string) and replace the @FF with it. @item @code{:display} control property This occurs when the primary format file cannot be determined. Normally, @code{edb-1int-to-single} looks for the filename of readable file first in the @code{:format-file} extra attribute, and then doing an ``EDB 1.x-style'' format-file search (@pxref{Auxiliary files}). The easiest way to fix this is to make sure a the format file (or a symlink to it) is named in such a way that the search can find it. For example, if the internal file layout filename is @file{foo.bar.baz}, make a symlink from the actual format file to @file{foo.bar.fmt}. @item primary format file's local variables block As mentioned above, an unrecognized @code{eval:} form is output anyway, but commented out. Included in the comment is a @FF{}. Unfortunately, no general translation approach suggests itself since the form can be arbitrary Lisp code. If you are lucky, the form will be functionally redundant with one of the written control properties and you can simply delete it. The @code{VAR: VAL} variables listed above likewise have a @FF included in their comment. For @code{edb-data-coding}, you can copy its value to the first line. For @code{dbf-format-name-spec-alist}, you need to manually create new a @code{:display} block for each format named [lame ---ttn]. For the others, where the control property value is a function of some sort, you need to change the function to fit the expected calling convention of the associated control property [explain! ---ttn]. @end table @node Delimited file layout @section Delimited file layout @cindex file layout, delimited @cindex data file layout, delimited @cindex delimited file layout @cindex tab-separated text file layout EDB can conveniently read and write database files in which records are separated from one another by a record delimiter and, within each record, fields are separated by a field delimiter. When the delimiters are the newline and tab characters, respectively, the result is the standard @dfn{tab-separated text} layout, which is often used for transferring information from one program to another. @cindex delimiters, record and field @cindex record delimiters @cindex field delimiters The record and field delimiters need not be single characters; they can be arbitrary strings or even regular expressions. The latter is useful if the exact delimiter is not known ahead of time (for example, if records may be separated by one or more newlines). This regular expression mechanism can only be used when reading the database: when writing a database, all the record delimiters are identical, and so are all field delimiters. (Exception: you may specify an arbitrary record-writing function (@pxref{Nonregular file layout}) and arbitrary functions for either reading records or for separating records or fields in delimited layout, but should use the simpler reading mechanisms whenever possible, for your own sake.) Using a delimited file layout has one important consequence: the delimiter strings may not appear in the data, lest those occurrences be misinterpreted as delimiters rather than as data. For solutions to this, @xref{Resolving ambiguities}. @menu * How to specify delimited file layouts:: * Resolving ambiguities:: * Problems with end-of-file newlines:: @end menu @node How to specify delimited file layouts @subsection How to specify delimited file layouts @cindex separator, setting record @cindex separator, setting field @cindex record separator, setting @cindex field separator, setting If the data source can be represented as text in a buffer, and is amenable to separation using textual methods --- by recognizing a string, by matching against a regular expression, or by calling a stylized parsing function --- then it is said to be stored in a @dfn{delimited layout}. Reading involves determining record and field boundaries followed by parsing the data fields. Writing involves inserting into an empty buffer representations of record and field boundaries interleaved with those of the data (and then saving the buffer to disk). The control properties (@pxref{Control properties reference}), in order of importance for determining record boundaries when reading are: @code{:record-separator-function} followed by @code{:record-terminator} followed by @code{:record-separator}. For fields, the only applicable control property is @code{:field-separator}. @cindex beginning of file, text at @cindex end of file, text at To specify text at the beginning and/or end of the data (or at the beginning and/or end of each record) to ignore, use the @code{:cruft} control property. When writing, those control properties that specify a regexp vector (@pxref{Kinds of control property values}), must specify the last element (a literal string), since it is not possible to reliably derive such a string from the regular expression and submatch information given in the first two elements of the vector. For instance, suppose a database has records with a variable number of fields separated by newlines, that records are also separated by newlines, and that the first field of each record has some special form different from all other fields (say, it is a number with a decimal part). The following code would permit separation of the records without writing a special function to do so and without including the decimal number in the separating text: @lisp :record-separator ["\\(\n\\)[0-9]+\\.[0-9]+" 1 "\n"] @end lisp Be careful to use a correct value for separator strings. For instance, if your record separator is a form feed on a line by itself, you probably want to set @code{:record-separator} to @samp{"\f\n"}, or possibly @samp{"\n\f\n"}, rather than just @samp{"\f"}, lest the newlines be considered to be part of the records rather than part of the separator. @subsubsection More examples For instance, to parse "[Mary, John,Jack, and Jill]" and to write it back out as "[Mary, John, Jack, Jill]", the following specification would suffice: @lisp :record-separator [", *\\(and +\\)?" 0 ", "] :cruft [["[" "]"] [nil nil]] @end lisp [[[ This following example should go away when writing is converted from ``all or nothing'' to ``selective update''. The -string slots are used for writing; but what if you only have a regexp for the leading or trailing junk, but you want that restored exactly? You can set pre-first-string *after* the database file has been found. For instance, in db-before-read-hooks, use a function such as @lisp (defun btxdb:read-comments () (save-excursion (set-buffer db-buffer) (goto-char (point-min)) (when (search-forward "@@" nil t) (setf (sepinfo-pre-first-string (database-record-sepinfo database)) (buffer-substring (point-min) (point)))))) @end lisp or even put @lisp (setf (sepinfo-post-last-string (database-record-sepinfo database)) (with-current-buffer db-buffer (goto-char (point-min)) (re-search-forward "\n\C-l\n") (buffer-substring (match-beginning 0) (point-max)))) @end lisp as is in your auxiliary file. ]]] If all records have five lines (say), you can use: @lisp :record-separator-function (db-make-n-line-sep-function 5) @end lisp This is also useful when both the field separator and the record separator are the newline character. @defun db-make-n-line-sep-function n Return a function useful when all records have exactly @var{n} lines. @end defun @node Resolving ambiguities @subsection Resolving ambiguities @cindex resolving ambiguities in database files @cindex ambiguities in database files, resolving Substitution is a mechanism for dealing with the problem of distinguishing field and record separators from the contents of database records. For instance, if the newline character (actually, a string consisting of only the newline character) is used as a record separator, and records may contain multiline text fields (or other fields whose storage representation contains a newline), then how would EDB know, when reading the database back in, which newlines are record separators and which are part of fields? There are several ways to avoid this ambiguity. @itemize @bullet @item Disallow the use in record fields of the character or string causing the ambiguity. For instance, in the example above, you might change the record field type of all of the string fields to one-line-string. @item Change the separator(s) to strings that do not appear in the storage representation of any field. For instance, Unix password files are stored in delimited file layout with a colon as the field delimiter (and colons are prohibited from appearing in the field text). @lisp :field-separator ":" @end lisp Strings containing non-printing characters are another good bet, but this method relies on luck and the hope that the chosen separators will never appear in data. @item Change the representation of the ambiguous string, when it appears in data; this guarantees that whenever the string does appear in a database file, it stands for a separator. This scheme is called substitution, because another string is substituted for the ambiguous one when it appears in data. This is similar to the previous workaround, which changed the separators rather than the data-bearing instances of the string. Ambiguities are still possible, if the substituted text happens to appear elsewhere in data. Specifying a substitution is described below. @item The simplest solution is to use EDB's internal file layout (@pxref{Internal file layout}). Ambiguities can only occur when the field data and the separators are both text to be interpreted by EDB@. EDB's internal file layout uses Emacs Lisp's mechanisms (a built-in form of quoting) to ensure that what is read in is identical to what was written out. @end itemize @cindex substitution, in reading a database file Substitution is the replacement of potentially ambiguous strings by other ones. For instance, when writing tab-separated text, each occurrence of the newline character in a field could be replaced by control-k when the database is written. Then, when the file is read in, every newline can be safely assumed to be a record separator. The final step is converting the control-k characters back into newlines. The problem with this approach is that if there were any control-k characters in the text, then when the database is read back in, they will be (incorrectly) converted to newlines. EDB warns when the database is being written out if this problem could occur; you may choose a different substitution or abort the database write operation. It is usually possible to find a substitution --- a character or sequence of characters that doesn't appear in the data. The @code{:substitutions} control property specifies a vector of string pairs: @code{(DATA . FILE)}. For example, to make control-k in the database file stand for newline in the data, include in the control: @lisp :substitutions [("\n" . "\C-k")] @end lisp @node Problems with end-of-file newlines @subsection Problems with end-of-file newlines @cindex newline, at end of database file Suppose you want to get rid of every newline at the end of the database file, but you don't know how many there are. @lisp :cruft [[nil ["\n*\\'" 0 "\n"]] [nil nil]] @end lisp does not work, because the post-last-record regexp is searched for backward from the end of the buffer, and (because of the way that @code{regexp-search-backward} is implemented) the backwards regexp match for @samp{\n*} is always the empty string! The proper way to write this is @lisp :cruft [[nil ["[^\n]\\(\n*\\'\\)" 1 "\n"]] [nil nil]] @end lisp @xref{Control properties reference}. @node Tagged file layout @section Tagged file layout @cindex file layout, tagged @cindex data file layout, tagged @cindex tagged file layout Another popular file layout supported by EDB is that of field values preceded by the fieldname. For instance, a record might be represented in the file by @example Where:Here When: Now What: This! @end example which indicates a record in which the `where', `when', and `here' fields have the specified values. Tagged files are a special case of files in nonregular layout; EDB supports them specially (@pxref{Nonregular file layout}). To read a database file in tagged format, call the function @code{db-tagged-setup} in the database's format or auxiliary file. Its argument specifies the names of the fields and the tags that precede them in the database file. This function is called automatically when the @code{:tagged-setup} control property is specified. @defun db-tagged-setup fspecs [attrs...] Ready the database to read files in tagged format. Argument @var{fspecs} is a list of tagged-field specifications, one for each field in a database record. Each tagged-field specification is a three-element list of the field name (a symbol), the tag used to identify it in the file (a string), and a brief help string. Instead of a symbol, the tagged-field name may be a cons of the field name and its type. To indicate that a field is never found in the input file (typically because it is computed on the fly), use nil for its tag. @var{attrs} is a sequence of alternating keywords and values specifying overriding attributes. Note: Do not call @code{database-set-fieldnames-to-list} if you call this function. @end defun Calling @code{db-tagged-setup} sets the database's field names, installs appropriate functions for reading and writing the database, and allows you to set attributes specific to a tagged database. For example, you can customize the behavior of the parsing and output functions with respect to what characters can appear in a tag, what the separator between tag and value looks like, and how continuation lines are handled. By default, records are separated by blank lines, tags are separated from field values by @samp{:}, white space around the separator is not significant on input, the separator is followed by one tab on output, and continuation lines start with whitespace. Some attributes permit arbitrary manipulations of records; for instance, if a database nearly conforms to the tagged file model, these can be used to customize the behavior of the existing tagged code. One way to do this is to set @code{:pre-parse-thunk} to a function that removes the field from the file representation before the record is parsed, and @code{:post-write-function} to a function to modify the automatically generated tagged file representation for that field. When using the tagged file layout, you should not (due to implementation restrictions) set variable @code{db-after-read-hooks} (@pxref{Read hooks}). Instead, use the attribute @code{:index-function}. The following keywords are recognized in as part of the @var{attrs} argument to @code{db-tagged-setup}. Unless otherwise specified, the default value is @code{nil}. @macro tskeyword{name} @item \name\ @vindex \name\ db-tagged-setup keyword @end macro @table @code @tskeyword{:tag-chars} The characters that are allowed in field tags, in a string suitable for placing inside @code{[]} in a regular expression. Default value: @code{-_A-Za-z}. @tskeyword{:separator} The string that separates field names from values. Used only if @code{:separator-regexp} or @code{:separator-output} is @code{nil} (depending on whether the record is being read or written). Default value: @code{:}. @tskeyword{:separator-regexp} A regexp for the separator between field names and values when parsing. @tskeyword{:separator-output} The separator between field names and values on output. @tskeyword{:continuation} The string that marks (the beginning of) a continuation line. Used only if @code{:continuation-regexp} or @code{:continuation-output} is @code{nil} (depending on whether the record is being read or written). Default value: @code{\t}. @tskeyword{:continuation-regexp} A regexp for a continuation line in a value when parsing. Default value: @code{[ \t]+}. @tskeyword{:continuation-output} The fixed string to use (before) continuing values on output. @tskeyword{:pre-parse-thunk} On read, a function called with no arguments immediately prior to the tagged parsing. The buffer is narrowed to the region representing the current record. @tskeyword{:index-function} On read, a function called with one arg @var{database}, after all the records are parsed and converted from stored strings to actual objects. This is useful for doing accounting chores, such as indexing, on the entire set of records (@pxref{Mapping over the database}). @tskeyword{:pre-write-function} On write, called with one arg @var{record} before tagged writing. Point is where the record will be inserted in the buffer. @tskeyword{:post-write-function} On write, called with one arg @var{record} after tagged writing. Point is immediately after the file representation of the record. @tskeyword{:default-field} A fieldname (symbol) for the field indicated by an illegal or empty tag. (For instance, you might set it to @code{comments}.) If @code{nil}, those values are discarded. @end table @unmacro tskeyword @node Relational file layout @section Relational file layout @cindex file layout, relational @cindex data file layout, relational @cindex relational file layout [This node's documentation is poor primarily because, lacking examples of db-rdb.el usage to study, we make uninformed guesses. ---ttn] The @file{db-rdb} library provides some functions for treating a database in a manner that allows correlation between fields, also known as relational capabilities, once the data is completely loaded into memory. On disk, the data must be stored in a variation of tagged file layout (@pxref{Tagged file layout}). To access this kind of database, use @code{db-rdb-setup}. To correlate fields, use @code{db-rdb-correlate-field-defs}. @findex db-rdb-database-stored->actual @findex db-rdb-list-rrfr @findex db-rdb-list-wrfr @findex db-rdb-read-fields Other (possibly useful) functions: @code{db-rdb-database-stored->actual}, @code{db-rdb-list-rrfr}, @code{db-rdb-list-wrfr}, and @code{db-rdb-read-fields}. @defun db-rdb-setup rfspecs &optional lock-flag Ready the database to read files in RDB format. This creates database local variables and sets database slots. @var{rfspecs} is a list of rdb-field specifications, one for each field in a database record. Optional, second argument @var{lock-flag} should be non-@code{nil} to lock the file for synchronized updates. The locking and unlocking is done with external programs @file{rdblock} and @file{rdbunlock}, which must be available in the current PATH environment variable. Each field specification is a three-element list of the field name (a symbol), the tag used to identify it in the file (a string), and a brief help string. Instead of a symbol, the rdb-field name may be a two-element list of the field name its type. To indicate that a field is never found in the input file (typically because it is computed on the fly), use @code{nil} for its tag. @end defun @defun db-rdb-correlate-field-defs ifields efields Correlate the @var{ifields} (internal fields) and @var{efields} (external fields) with each other and produce a field list suitable for @code{M-x db-rdb-setup}. @var{ifields} is a list: @code{((@var{handle} @var{name} @var{help})...)}, where @var{handle} is either @code{(@var{symbol} . @var{type})} or just @var{symbol}. @var{efields} is a list: @code{((@var{name} @var{width} @var{format} @var{help})...)}, produced by the function @code{rdb-read-field-defs}. If @var{type} is hidden, it is deduced from the corresponding @var{format}. Similarly, if the internal @var{help} is hidden, any external @var{help} is used. The internal definition always overrides the external, since it is more specific to the EDB implementation. The resulting list format is: @code{(((@var{symbol} . @var{type}) @var{name} @var{help})...)}. @end defun @node Nonregular file layout @section Nonregular file layout @cindex file layout, nonregular @cindex data file layout, nonregular @cindex nonregular file layout Unlike most databases, EDB can work with data stored in any file layout whatever --- so long as you specify how the information is to be extracted. If the file layout is too complicated to be described by regular expressions describing the record and field separators and their context (@pxref{Delimited file layout}), then you may write Emacs Lisp code which extracts the information from the database file. The great advantage of this mechanism is that it permits you to maintain your current files, in exactly their current file layouts, and to keep the same tools and habits you've accumulated, but also to manipulate them in a structured way with EDB@. For instance, you might wish to maintain the database file in a file format easy for people to read all the time, rather than having to create a report for that purpose. Three pieces of information must be provided: how to find the extent of a file record, how to read a file record, and how to write a file record. The third may be omitted if the database is only being read in the custom file layout (and will be saved in some more tractable file format). If the second is provided (that is, the @code{:read-record} control property is specified), then the file will be assumed to be in a nonregular file layout and the function specified is used to read the database, no matter what other information is provided. Information about how to separate one record from another within the file is specified by the usual control properties (@pxref{Control properties reference}). In many cases, even if the file layout of the data is nonregular, it is easiest to describe the record separator with a string or a regexp. For more details, @xref{Delimited file layout}. You may also specify a @code{:record-separator-function} control property. The function should take one argument, the end of the previous record (@code{nil} the first time it's called), and return a pair whose car is the end of the current record and whose cdr is the start of the next record (@code{nil} if there is no next record in the file). The function specified for the @code{:read-record} control property is called with no arguments with the current buffer narrowed to a single file record (that is, narrowed to the representation of a single database record). It should parse the database's file layout and return a record initializer (@pxref{Kinds of control property values}). The function specified for the @code{:write-record} control property takes zero or more args. If zero, the record's values are dynamically bound to variables whose names are the field names. If non-zero, the function's arglist specifies those fields whose values are to be passed in. (This latter case is useful if some fields are computed.) The function should insert the file representation of that record in the current buffer. If @code{:write-record} is not specified (and the data is not in internal layout format), then the field separator and record separator information, if present, is used to write the record (@pxref{Delimited file layout}). This permits the use of a simple, delimited output file layout with a more flexible input file layout. Tagged format is a special case of nonregular file layout for which EDB provides support (@pxref{Tagged file layout}). Another example is given below. @menu * Nonregular database example:: @end menu @node Nonregular database example @subsection Example of database in nonregular file layout Here is a simple example of a database in a nonregular file layout; this does not mean that the file representation of each record is vastly different from the others (it may be, but is not in this instance), but that there is no regular rule for extracting field values from the record. Suppose we had a database with fields @samp{place}, @samp{time}, and @samp{purpose}, whose database file was: @example Dentist's Office at Never! for Root canal Home at Midnight for Sleep Other places at Other times for Other things @end example In order to read and write this database, place the following code in the auxiliary file (@pxref{Reading from disk}): @lisp (setf (database-read-record-from-region database) 'arb-demo-rrfr (database-write-region-from-record database) 'arb-demo-wrfr) (defun arb-demo-rrfr () (unless (re-search-forward "\\(.*\\)\s-+at\\s-+\\(.*\\)\s-+for\\s-+\\(.*\\)") (error "This didn't look right to me.")) (list 'place (match-string 1) 'time (match-string 2) 'purpose (match-string 3))) (defun arb-demo-wrfr (record) (insert (db-record-field record 'place) " at " (db-record-field record 'time) " for " (db-record-field record 'purpose))) @end lisp The auxiliary file would also specify the database's field names: @lisp (database-set-fieldnames-to-list database '(place time purpose)) @end lisp as well as possibly other information such as the summary format or the name of the default format file. See the example database auxiliary file @file{arb-demo.dba} for a concrete example of this. All this Emacs Lisp code may be placed in the local variables section of the format file instead of in the auxiliary file, if desired. For more information about the local variables section of a file, @xref{File Variables, , , emacs, The GNU Emacs Manual}. @cindex local variables section, format file This particular example is simple enough that a special function for reading isn't strictly necessary. Reading can be done under the control of regular expressions; for instance, each field separator would be @code{"\\s-+\\(at\\|for\\)\\s-+"}. See the example database auxiliary file @file{arb-demo-regexp.dba} for a concrete example of this. You would still need to specify a special record-writing function. Here is another example, which has no field separators; in the data file, the fields abut one another. While it, too, could be read and written under the control of regular expressions, the use of functions is a bit clearer. @cindex Einstein, Albert @cindex Botswana The data file is: @example Einsteinbirthday03141879 Botswanaindepend09301966 @end example The auxiliary file contains the following: @lisp (setf (database-print-name database) "Historic Dates") (database-set-fieldnames-to-list database '(name occasion month day year)) (setf (sepinfo-sep-string (database-record-sepinfo database)) "\n") (setf (database-read-record-from-region database) 'sized-field-rrfr (database-write-region-from-record database) 'sized-field-wrfr) (defvar sized-field-alist '((name . 8) (occasion . 8) (month . 2) (day . 2) (year . 4))) (defun sized-field-rrfr () (let ((field-begin (point)) pl) (dolist (this-size-cons sized-field-alist) (forward-char (cdr this-size-cons)) (push (buffer-substring field-begin (point)) pl) (push (car this-size-cons) pl) (setq field-begin (point))) (unless (eobp) (error "Found extra characters in this record.")) pl)) (defun sized-field-wrfr (record) (mapcar (lambda (this-size-cons) (let ((v (db-record-field record (car this-size-cons)))) (if (not (= (length v) (cdr this-size-cons))) (error "Field %s value %S has length %d (should be %d)." (car this-size-cons) v (length v) (cdr this-size-cons))) (insert v))) sized-field-alist)) @end lisp This example is actually a bit too simple. Some of the fields could be made non-strings, field constraints should keep the fields the right length, and @code{sized-field-alist} should be a database-local variable. @node Reading from disk @section What happens when a database is read in from disk @cindex reading from disk, details In brief, the following happens after you execute @code{db-find-file}: @enumerate @item If the database is already read in and its buffer has not been killed, the buffer is simply selected. No other work is done. @item Otherwise, the database file is inserted in a special buffer of its own. If the database is in EDB internal file layout (that is, if an identifying header is found), it is read in immediately. Otherwise, a new, empty database is created. In either case the dynamic variable @code{database} is bound; this makes it possible to refer to the database in the auxiliary and format files (even before it has been read in, if it is not in EDB internal file layout). @item The format file is found (@pxref{Auxiliary files}), and the data display buffer is created. @item Perform the rest of the work necessary for setting up the data display buffer (everything up to the running of @code{db-before-read-hooks}). The first action is to insert the format file's contents into the data display buffer. @item The auxiliary file, if any, is loaded. This happens in the data display buffer, and the dynamic variable @code{database} is bound to the current database. For more information about how the auxiliary file is found and what it can do, @xref{Auxiliary files}. The auxiliary file is not read every time the previous step occurs, only when a database's primary display format is read. (The primary display format is the one initially selected when a database is first read in.) @item The local variables section, if any, of the format file is executed; this may set variables and execute Emacs Lisp code, exactly analogously to the auxiliary file. EDB ignores the value of @code{inhibit-local-variables} when evaluating this code. This section is then deleted from the working copy of the file, so that it does not appear in the data display buffer when you view database records. @xref{File Variables, , , emacs, The GNU Emacs Manual}, for more information about the local variables section of a file. @item Database information is propagated; for instance, the names of the database fields are known by now, and various other internal state is initialized depending on this information, if necessary. @item The format file is parsed, and literal text and formatting directives are distinguished from one another. This completes the preparation of the data display buffer. @item Run @code{db-before-read-hooks}. @item If the database had already been read because it was stored in internal file layout, it is massaged a bit to get it into its final form. Otherwise, the database is finally read; the values of the @code{:record-FOO} and @code{:field-separator} control properties determine whether the layout is delimited or nonregular and direct the parsing. The @code{:substitutions} control property directs replacement of characters that could not be written into the file, and the @code{stored->actual} slot of each record field type completes the translation to the data's internal format from its file layout. @item Run @code{db-after-read-hooks}. @item The database has now been read and is in its final form. The first record of the database is displayed in the data display buffer, which is then placed in view mode and selected (made visible). @end enumerate @node How information is displayed @chapter How information is displayed @cindex display format, specifying The display of information, both on the screen (whether in the data display buffer, the summary buffer, or elsewhere) and in other output (such as reports), is controlled by formatting commands. We will discuss a data display buffer by way of example; the formatting specifications are the same for summary buffers and reports as well. Display types should not be confused with record field types; a display type is used to specify how a particular value is shown on the screen, but a record field type constrains the information actually contained in the record field. This chapter does not discuss record field specifications, which specify everything about a record field type except how it is displayed and parsed in output intended for humans to read. For more information about that, and about the distinction between record field types and displaytypes (the latter of which is described in this chapter), @pxref{Record field types}. A display format gives all of the information necessary to create a data display buffer; it consists of literal text that is displayed as is (without possibility of editing) and of @dfn{display specification}s that instruct EDB how to display a particular field's contents. The display specifications do not appear in the data display buffer; they are replaced by fields' values, which may or may not be editable. An example of a display specification is @samp{\name,width=16}, which indicates that the @samp{name} field of the database should be displayed (after being padded or truncated to exactly 16 characters). When a format is first specified, it is parsed and the formatting information specified in the display specification strings is used to create a displayspec structure. @menu * Display specifications:: * Predefined displaytypes:: * Enumeration displaytypes:: * Defining new displaytypes:: * Display specification optional parameters:: @end menu @node Display specifications @section Display specifications @cindex display specification A @dfn{display specification} describes how a particular database record field appears in the data display buffer. An display specification consists of a backslash followed by a field name, plus perhaps some optional type and formatting information, plus optionally a backslash followed by a space. The items of extra formatting information must be separated from the field name and from each other by commas. No spaces or tabs may occur in a display specification. To specify a backslash which does not begin a display specification, but should appear in the data display buffer verbatim, precede it by another backslash. Here is a (quite complicated) example display format: @example \name,one-line-string,actual->display=upcase\ , \occupation' Pay: \\\salary,min-width=4: too much! Address: \address,indent is home sweet home @end example This display format is valid if the database contains fields called @samp{name}, @samp{occupation}, @samp{salary}, and @samp{address}; any other fields are not displayed. Some typical records would be displayed like this: @example JOHN DOE, butcher Pay: \ 22: too much! Address: 123 Main St. Anyplace, USA is home sweet home @end example @example JANE ROE, baker Pay: \4444444: too much! Address: 675 Massachusetts Avenue is home sweet home @end example The optional information includes the type of this display field and formatting directives for it; if the type is present, then it must come first among the displayspec's optional specifications. Each optional parameter is preceded by a comma to separate it from the preceding one (or from the fieldname, for the first optional parameter). The optional information is typically of the form @samp{@var{slotname}=@var{value}}, which sets the specified slot to the given value, or @samp{@var{slotsetter}}, which sets some slot to a particular value. Explicitly specified formatting information overrides any defaults. For a list of slotnames and slotsetters, @pxref{Display specification optional parameters}. The display type can be specified by writing the typename (such as @samp{string} or @samp{integer}) as the first optional parameter. @cindex displaytype, not set by display specification The display type specifies default values for the display specification (actually for the displayspec structure, which is derived from the display specification). It is rarely necessary even to specify the displaytype --- most display specifications consist of simply a backslash and a fieldname --- since if the displaytype is omitted then a displaytype with the same name as the record field type (actually the @code{:type} attribute of the record field type) is used. This works because typically displaytypes and recordfieldtypes with the same names and complementary definitions are declared at the same time. The displaytype must be compatible with the record field type; it is an error to specify a displaytype of @samp{integer} when the data is actually a string. @code{database-set-fieldnames-to-list} to specify recordfieldtypes; @pxref{Specifying a record field type}. @node Predefined displaytypes @section Predefined displaytypes @cindex displaytypes, predefined @cindex type, display, predefined @cindex predefined displaytypes The following displaytypes are predefined. Most of them correspond directly with the same-named record field type; @xref{Predefined record field types}. You can also define displaytypes of your own; @xref{Defining new displaytypes}. @macro dtype{name} @item \name\ @cindex \name\ displaytype @end macro @macro dtypex{name} @itemx \name\ @cindex \name\ displaytype @end macro @subsection Builtin These displaytypes are available as soon as EDB is loaded. @table @code @dtype integer Ordinary integers. @dtype integer-or-nil Integers or @code{nil}, the empty value; @code{nil} is formatted as the empty string. @dtype number @cindex floating-point number displaytype Ordinary numbers. A number is an integer or a floating-point number. @dtype number-or-nil Numbers or @code{nil}, the empty value; @code{nil} is formatted as the empty string. @dtype yes-no This displayspec corresponds to the @code{boolean} recordfieldtype. The field is three characters long and contains ``Yes'' or @w{``No ''}. @dtype string Ordinary strings. By default there is no maximum or minimum width or height, and subsequent lines are indented relative to the first character of the first line. @dtype one-line-string Strings which may not contain newlines. @dtype string-or-nil Either a string or the value @code{nil}, which is displayed as the empty string. @dtype nil-or-string Either a string or the value @code{nil}. When you enter the empty string as the field value, or when a new record is created, the value @code{nil} is used in preference to the empty string. @dtype one-line-string-or-nil Either the value @code{nil} or a string which may not contain newlines. @end table @subsection From @file{edb-t-timedate1.el} Loading @file{edb-t-timedate1.el} provides additional displaytypes, and related functions. @table @code @dtype date @findex edb-t-timedate1:date-year @findex edb-t-timedate1:date-month @findex edb-t-timedate1:date-day A date which specifies zero or more of the year, month, and day; any or all of these components may be hidden. The date is created by the constructor @code{edb-t-timedate1:make-date} and a date's components are retrieved using the selectors @code{edb-t-timedate1:date-year}, @code{edb-t-timedate1:date-month}, and @code{edb-t-timedate1:date-day}. A date is formatted by @code{edb-t-timedate1:format-date} and parsed by @code{edb-t-timedate1:parse-date-string}. @defun edb-t-timedate1:make-date year month day Make an EDB date object representing @var{year}, @var{month}, and day @var{day} (all integers). @end defun @findex edb-t-timedate1:parse-date-default-function @defun edb-t-timedate1:parse-date-string s Parse string @var{s}, and return an EDB 1.x date object. Signal error if the parse is invalid. If @var{s} contains only whitespace, return a null date object. If @var{s} is @code{nil}, use the result of calling @code{edb-t-timedate1:parse-date-default-function} instead. @end defun @defun edb-t-timedate1:format-date fmtstr &optional date Using @var{fmtstr}, format the @var{date}, which defaults to the current date if @code{nil}. @var{fmtstr} can contain the following symbol strings, which are substituted by their corresponding value from the date; other characters are inserted as-is. @table @samp @item %d day of month --- 1 to 31 (one or two digits) @item %dd day of month --- 01 to 31 (always two digits) @item %m month of year - 1 to 12 (one or two digits) @item %mm month of year - 01 to 12 (always two digits) @item %mon month name (abbreviated) - Jun @item %month full month name - June @item %yy last 2 digits of year - 00 to 99 @item %year year as 4 digits --- 0000 to 9999 @item %jday Julian day of year --- 1 to 366 @item %wday day of week --- 0 to 6 (Sunday = 0) @item %day day of week name --- ``Sun'' to ``Sat'' @item %weekday full day of week name --- ``Sunday'' to ``Saturday'' @end table See the variables @code{edb-t-timedate1:format-date-sub-syms-alist} and @code{edb-t-timedate1:format-date-sub-syms-regexp}. A special case: if an element of @var{date} is @code{nil}, its field is hidden. A @var{date} object of all @code{nil}s is thus formatted as the empty string. @end defun @defun edb-t-timedate1:simple-format-date date Format the @var{date} using a default format, defined by the variable @code{edb-t-timedate1:simple-format-date-default}. If @var{date} is @code{nil}, use the value of @code{edb-t-timedate1:parse-date-default-function}. @end defun @item date-mmddyy "/" @cindex date-mmddyy displaytype @itemx date-yymmdd "" (empty string) @cindex date-yymmdd displaytype @itemx date-ddmmyy "." @cindex date-ddmmyy displaytype @itemx date-ddmmmyy " " (space) @cindex date-ddmmmyy displaytype @itemx date-yyyymmdd "/" @cindex date-yyyymmdd displaytype These are based on the @code{date} displaytype, and are meant to be used in a display spec, such as: @example \datefield,date-mmddyy @end example The formatting for each @code{date-@var{foo}} is done by a function @code{edb-t-timedate1:format-date-@var{foo}}, for example @code{date-mmddyy} and @code{edb-t-timedate1:format-date-mmddyy}. These functions all accept an optional second arg @var{separator} that can be used to override the default (shown after the name above). @dtype date-iso @dtypex date-europe @dtypex date-full @dtypex date-all @dtypex date-unix @dtypex date-dec More @code{date}-based displaytypes, similar to the previous group, except that the associated functions take only one arg (the date). @dtype time @findex edb-t-timedate1:format-time @findex edb-t-timedate1:parse-time-string A time which specifies zero or more of the hour, minute, and second. The time is formatted by @code{edb-t-timedate1:format-time} and parsed by @code{edb-t-timedate1:parse-time-string}. The time is created by the constructor @code{edb-t-timedate1:make-time} and a time's components are retrieved using the selectors @code{edb-t-timedate1:time-hours}, @code{edb-t-timedate1:time-mins}, and @code{edb-t-timedate1:time-secs}. A time is formatted by a @code{edb-t-timedate1:format-time-@var{spec}} function and parsed by @code{edb-t-timedate1:parse-time-string}. @defun edb-t-timedate1:make-time hours mins secs Make an EDB time object representing @var{hours}, @var{mins}, and day @var{secs} (all integers). @end defun @findex edb-t-timedate1:parse-time-default-function @defun edb-t-timedate1:parse-time-string s Parse the first occurrence of @code{hh:mm:ss} in string @var{s}; return a time object. If ``:ss'' is hidden in @var{s}, the seconds default to zero. If @var{s} contains only whitespace, return an empty time object. If @var{s} is @code{nil}, use instead the result of @code{edb-t-timedate1:parse-time-default-function}. @end defun @defun edb-t-timedate1:format-time-12 time @defunx edb-t-timedate1:format-time-24 time @defunx edb-t-timedate1:format-time-hhmm time @defunx edb-t-timedate1:format-time-12-hhmm time @defunx edb-t-timedate1:format-time-24-hhmm time Format @var{time} in various ways. @end defun @end table @unmacro dtypex @unmacro dtype @node Enumeration displaytypes @section Enumeration types @cindex enumeration types An enumeration displaytype is used for fields whose values are one of a fixed set of alternatives. Each alternative consists of an entire string entered in the minibuffer with completion. (The string may consist of only a single character, but you must still type @key{RET} after entering the string. Also, @key{TAB} completes a partly-entered choice, and @key{?} lists the remaining possibilities. @xref{Completion, , , emacs, The GNU Emacs Manual}, for more about completion.) The internal representation of the data --- its recordtype --- need have nothing to do with the way that the alternatives are specified. This section describes the enumeration displaytype, which is nicknamed @dfn{enum}. The internal, input, display, and file storage representations of the value may all be different. This displaytype is created by calling the following function, which also creates a corresponding recordfieldtype. @defun edb-define-enumtype typename alternatives [optstring] Make @var{typename} (a symbol or string) an enumerated type. Both a displaytype and a recordfieldtype are created. @var{alternatives} is a list. Each alternative is a list of up to four components: the internal representation, any constant Lisp object, often a string; the input representation input interactively to specify this alternative, a string or list of strings (for multiple input representations); the display representation, a string; and the file storage representation, a string. If the input representation is omitted and the internal representation is a string, that string is used. If the display representation is omitted, it defaults to the first input representation. The display representation is automatically also a valid input representation. If the file storage representation is omitted, it defaults to the display representation. If all the other components are omitted, the internal representation string may be used in place of a one-element list containing just it. Optional argument @var{optstring} is a displayspec option string. @end defun When a record field's type is an enum type, it can be assumed that the value in the record field is one of the valid representations. (Similarly, when a field's type is string, EDB can assume that the field content is actually a string.) This means that the empty string, @code{nil}, and other special values must be specifically mentioned when the enumeration type is defined. Here is a way to define an enumeration type which is either a day of the week or the empty string: @lisp (edb-define-enumtype 'workday '("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "")) @end lisp If it is possible for the field value to be @code{nil} (but not the empty string) after reading the database, and @code{nil} should be displayed as @samp{Unknown} (and that string parsed into a value of @code{nil}), the following definition suffices: @lisp (edb-define-enumtype 'workday '("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" (nil "Unknown"))) @end lisp @node Defining new displaytypes @section Defining new displaytypes @cindex displaytype, defining @cindex type, display, defining @cindex defining displaytypes When you are about to type a complicated display specification --- or a simple one more than once --- consider defining and using a displaytype instead. Displaytypes are more concise (and so less cumbersome and less error-prone), easier to change (since a change to the displaytype can affect every display specification that uses it), and clearer (since a descriptive typename makes immediately clear what the intention is). Furthermore, displaytypes can be built up incrementally, with each one making a few changes to those from which it inherits defaults. Use @code{edb-define-displaytype} to define a new displaytype. @defun edb-define-displaytype name source [override...] Define a displaytype @var{name} (a symbol) with @var{source}. @var{source} may be a displayspec, the name (a symbol) of a currently defined type, a string representing the optional parameters part of a displayspec, or nil. In all cases, a new displayspec object is created and then modified by @var{override}, a sequence of alternating keywords and values, and finally added to a global list. Return @var{name}. @end defun @node Display specification optional parameters @section Display specification optional parameters @cindex display specification optional parameters @cindex displayspec fields This section describes the display specification optional parameters, which correspond exactly to slots of the displayspec, EDB's internal representation of the display specification. @cindex slotsetters, for display specifications @cindex slot assigners, for display specifications Optional display specification parameters are separated only by commas; display specifications never contain whitespace. These parameters are of two forms: slotsetters, which are a single word and set a slot to a particular value; and slot assigners, which are of the form @samp{@var{slotname}=@var{value}} and set the slot to the value. Unless otherwise specified, each slot can be set by a slot assigner whose name is the same as that of the slot. An example of a display specification containing two optional parameters, one a slot assigner and one a slotsetter, is @samp{\name,width=16,unreachable}. Display specification fields are processed in order, so only the last instance of a particular parameter has any effect. Any explicitly specified parameter overrides defaults, values inferred from the type, or previously specified parameters. If you find yourself repeatedly writing similar display specifications, or large, bulky display specifications, consider defining a new type to do some or all of the work for you; @xref{Defining new displaytypes}. @cindex displayspec structure @macro dslot{name} @item \name\ @cindex @code{\name\} displayspec slot @end macro @macro dslotx{name} @itemx \name\ @cindex @code{\name\} displayspec slot @end macro @table @code @dslot record-index @cindex record field index This integer is the field index in a database record of the value formatted by this displayspec. This is set by looking up the fieldname part of the displayspec. @dslot indent @cindex @code{noindent} display specification parameter This boolean value determines whether the second and subsequent lines should align with the beginning of the first one or should be flush left, in column 0. It is set and unset with the @code{indent} and @code{noindent} slotsetters. The first of the following displays has indent set, and the second does not: @example Name: John Doe Address: 123 Main St. Anyplace, USA @end example @example Name: John Doe Address: 123 Main St. Anyplace, USA @end example This causes alignment of the first character of subsequent lines with the first character of the first line; it does not do anything clever with whitespace in the field value, nor does it align different lines differently. @dslot min-width @dslotx max-width @cindex @code{width} display specification parameter These integers are the minimum and maximum widths which the display may occupy. If the formatted value is too short, the function in the @code{padding-action} slot is called to lengthen and/or justify it. If the formatted value is too long, the function in the @code{truncation-display-action} slot is called to shorten it; if that slot is empty, the field is simply truncated. The @code{width} slot assigner sets both the @code{min-width} and @code{max-width} displayspec slots. The @code{min-length}, @code{max-length}, and @code{length} slot specifiers are synonyms for the @code{min-width}, @code{max-width}, and @code{width} slot specifiers. @dslot min-height @dslotx max-height @cindex @code{height} display specification parameter These are analogous to @code{min-width} and @code{max-width}, but for the number of lines occupied by the formatted value (actually, the number of newlines in the string, plus one). There is a @code{height} slot assigner which sets them both. @dslot truncation-display-action @cindex @code{trunc-display} display specification parameter This function helps reduce the size of the formatted value when it is too large to fit in the specified displayspec size. It defaults to simply truncating the formatted field to the maximum permissible size. It may also be set with the @code{trunc-display} slot assigner. At present, this function is only called if the formatted value is too wide; there is no analogous function called when it is too tall. @dslot padding-action @cindex justification of display fields @cindex left justification of display fields @cindex right justification of display fields @cindex @code{right-justify} display specification parameter @findex right-justify This function determines how a field that is too small for the displayspec (that is, the printed representation contains fewer characters than specified in the @code{min-width} slot) should be expanded to fit. The padding function takes three arguments: the minimum length, the unpadded display representation, and the length of that representation. The @code{padding-action} slot may also be set to a cons of a padding character and a padding direction: @code{nil} for left-justification (padding on the right), and non-@code{nil} for right-justification. (You cannot set the @code{padding-action} displayspec slot to a cons by using a display specification, since display specifications may not contain whitespace, so the easiest way to right-justify a single field is to use the @code{right-justify} slotsetter.) The default, which can also be obtained just by setting the slot to @code{nil}, is to pad on the right with space characters. @dslot actual->display @dslotx display->actual @cindex @code{a->d} display specification parameter @cindex @code{d->a} display specification parameter These functions convert between the data's internal representation and its displayed representation (a string). Other functions (such as those in the @code{truncation-display-action} and @code{padding-action} slots) may then be called on the result returned by the @code{actual->display} function. These slots may be set with the @code{a->d} and @code{d->a} slot assigners. The @code{display->actual} function takes either one argument or four arguments: either just the field text or the field text, the previous field value, the record being operated upon, and the record fieldnumber of the field in question. EDB ascertains at runtime how many arguments the function should be applied to. The old field value is passed in case it contains hidden (undisplayed) attributes that need to be preserved across changes. The other two arguments permit a particular @code{display->actual} function to be used for more than one field of a record, allow the field text parse to depend on other record field values, and provide for other complicated needs. Most @code{display->actual} functions can be specified to take a single argument. The @code{actual->display} function takes either one argument or three arguments: either just the field value or the field value, the record, and the record fieldnumber. EDB ascertains at runtime how many arguments the function should be applied to. The reasons the additional arguments may be specified are similar to those outlined above (for instance, to permit the displayed representation of a field to depend on other information in the record); most @code{actual->display} functions take just one argument --- for instance, @code{upcase} is a valid @code{actual->display} function. @dslot match-actual->display @dslotx match-display->actual These functions are like @code{actual->display} and @code{display->actual}, but are only invoked when reading a displaying a search specification. If they are not specified (as is usually the case), then the ordinary (@code{match-}-less) versions are used for search specifications as well. These slots should be set to symbols, not to functions proper; that is, to specify that function @code{foo} should be used, set the slot to @code{'foo}, not to @code{(function foo)}. @c mernst sez: I don't know that these belong in the displayspec, @c but I don't quite know where they do belong. @dslot truncation-editing-action @cindex @code{trunc-edit} display specification parameter This function specifies what to do when a field being edited is too large for the specified displayspec size; this action may be different from that taken when simply displaying the offending value. It may also be set with the @code{trunc-edit} slot assigner. @dslot reachablep @cindex uneditable fields in data display buffer @cindex @code{unreachable} display specification parameter A Boolean value determining whether movement commands should skip this display field. The @code{reachable} and @code{unreachable} slotsetters are used to assign a value to this slot. @end table @unmacro dslot @unmacro dslotx @node Customization @chapter Customization @cindex customization @menu * Auxiliary files:: * Hooks and customization functions:: * Global variables:: @end menu @node Auxiliary files @section Auxiliary and format files @cindex auxiliary file @cindex format file @cindex display format file name @cindex file name, for auxiliary file @cindex file name, for display format When using control properties, this section has no meaning (you can skip it), since aux file functionality is handled by the free-standing Lisp in the control file. EDB 2.x will not have handling for format and auxiliary information in separate files outside that provided by the @code{:display} control property and @code{load}. You can provide code to be executed when the database is read in (@pxref{Reading from disk}). The optional auxiliary file usually contains the code specific to a particular database, but the format file, which specifies the on-screen arrangement of fields of a record, can also contain such code. Since the auxiliary file is read after the format file has been found but before it has been parsed, neither file can specify the other. The format file can, however, load arbitrary files, which is nearly as good as being able to specify an auxiliary file. @cindex auxiliary file name EDB looks for a file with the same name as the database file, but ending with one of the suffixes in @code{db-aux-file-suffixes}. @defvar db-aux-file-suffixes List of auxiliary file suffixes; the basename is that of the database file. The suffixes are tried in order; the default is @code{(".dba" ".aux" "a")}. The @code{.} that may precede the extension must be specified explicitly. @end defvar @defvar db-aux-file-path List of directories (strings) to search, in order, for auxiliary files not found in the directory with their associated databases. @end defvar The auxiliary file is evaluated in the data display buffer and so can set variables local to that buffer, such as hooks (@pxref{Hooks and customization functions}). The database itself can be manipulated via the dynamic variable @code{database}. For instance, auxiliary files often set the name (a string) of their associated databases. Code in an auxiliary file should be specific to the particular database; more general code is best placed in a separate file which is @code{load}ed (or, better, @code{require}d) by the auxiliary file. For instance, if you want to permit EDB to manipulate files of type Foo, you should put all Emacs Lisp code that applies to every Foo file in one file (@file{db-foo.el}, say), and then put @code{(require 'db-foo)} in the auxiliary file associated with a particular Foo file. (Alternately, you may autoload a function that will be called in the auxiliary file; function @code{db-tagged-setup} is autoloaded from @file{db-tagged.el} in this manner.) Either technique keeps auxiliary files simple and small and makes Foo-specific code easier to debug, byte-compile, and load only once per session. These advantages easily outweigh the introduction of an extra file. Since the format file has not yet been interpreted, the auxiliary file could even change the contents of the buffer (and so the apparent contents of the format file); such extreme trickiness is only called for in special circumstances. @cindex format file name The format file can contain Emacs Lisp code in its local variables section; that code can do anything that code in the auxiliary file can do. EDB tries to find one based on the database file name and the suffixes in @code{db-format-file-suffixes}; if that doesn't work, you are prompted for a display format to use. @cindex format file, path to search @defvar db-format-file-suffixes List of format file suffixes; the basename is that of the database file. The suffixes are tried in order; the default is @code{(".dbf" ".fmt" "f")}. The @code{.} that may precede the extension must be specified explicitly. @end defvar @defvar db-format-file-path List of directories (strings) to search, in order, for format files not found in the directory with their associated databases. @end defvar Code in the format file is useful for customizations specific to a particular format (such as setting variables which are local to the data display buffer); they can also be used for database-specific customizations if the file will always be the primary (first-selected) format for the database. @node Hooks and customization functions @section Hooks and customization functions @cindex hooks @cindex customization functions The following sections describe EDB's hooks and customization functions. @xref{Hooks, , , emacs, The GNU Emacs Manual}. Many of these hooks are change hooks, which permit a function (or functions) to be run whenever a value changes. These change hooks may be divided into two basic types: format change hooks and record field type change hooks (however, the latter is not yet implemented and probably will never be). The former are associated with a particular display format and are invoked when the value in a particular field, or in any field, changes. The latter (which are not yet implemented) are associated with a record field type and are invoked whenever a database record slot of a particular type is changed. @menu * Read hooks:: * Database mode hooks:: * Record display hooks:: * Edit mode hooks:: * Display format change hooks:: @end menu @node Read hooks @subsection Read hooks The following two hooks are useful for causing database values seen by EDB to be different than those in the database file. The first can be used to modify the database file before it is read in; the second can be used to modify the database after it has been read in but before EDB displays it. @defvar db-before-read-hooks Normal hook run immediately before a database is first read but after all local variables are set. The hooks are run in the data display buffer with variable @code{database} bound. Variable @code{db-buffer} is bound to a buffer containing the database file. This is a global variable. If you set it to be specific to a particular database (for instance, in the format or auxiliary file), then consider having its last action be to reset the variable to @code{nil}. [Lame. ---ttn] @end defvar @defvar db-after-read-hooks Normal hook run after a database is completely read. The hooks are run in the data display buffer with variable @code{database} bound. For databases with nonregular layouts, you might put a call to @findex database-stored->actual @code{database-stored->actual} here, for instance. This is a global variable. If you set it to be specific to a particular database (for instance, in the format or auxiliary file), then consider having its last action be to reset the variable to @code{nil}. [Lame. ---ttn] @end defvar @node Database mode hooks @subsection Database mode hooks @cindex database mode hooks @cindex hooks, database modes EDB provides hooks that are run whenever the data display buffer is switched between Database View mode and Database Edit mode and which are run when a summary buffer is created. @defvar db-view-mode-hooks Normal hook run when Database View mode is entered. @end defvar @defvar db-edit-mode-hooks Normal hook run when Database Edit mode is entered. @end defvar @defvar database-summary-mode-hooks Normal hook run when switching to Database Summary mode. @end defvar When using control properties, you should use @code{:locals} variables with the same name instead of setting the Emacs Lisp variables either directly or with @code{add-hook}. For example, here is a @file{.edb} file fragment: @lisp (defun set-up-1 () (setq truncate-lines t)) (defun set-up-2 () (scroll-bar-mode 1)) :locals [ (database-summary-mode-hooks '(set-up-1 set-up-2)) ] @end lisp @noindent This arranges for the summary buffer to have a scroll bar and for its long lines to extend off screen. Note the square braces. @node Record display hooks @subsection Record display hooks @cindex record display hooks @cindex hooks, record display @cindex display format, data-dependent @cindex data-dependent display format The following function is run each time a record is about to be displayed. This variable is set automatically when either of the control properties @code{:before-display} or @code{:choose-display} is specified (@pxref{Control properties reference}). @defvar dbf-before-display-record-function A function called before a record is displayed. The function takes one argument, the record. This is a good place to put calls to @code{db-change-format}. @end defvar Here is an example of how you might use this: @lisp (defun set-format-from-data (record) (if (< 0 (db-record-field record 'net-profit)) (db-change-format "loss format" "~/acct/db/loss.fmt") (db-change-format "profit format" "~/acct/db/profit.fmt"))) (setq dbf-before-display-record-function 'set-format-from-data) @end lisp This uses two different display formats, depending on the value of one field of a record. As you move from record to record in the database, each one is shown using the appropriate display format. A preferable implementation hides the filenames from the calls to @code{db-change-format} and instead uses, in the format or auxiliary file, @lisp (setq dbf-format-name-spec-alist '(("loss format" . "~/acct/db/loss.fmt") ("profit format" . "~/acct/db/profit.fmt"))) @end lisp See the example file @file{arb-demo.dba} for an example of this. @code{dbf-format-name-spec-alist} need not specify the full pathnames if the format files are located in the same directory as the database or if @samp{"~/acct/db"} is placed in @code{db-format-file-path}. Finally, you would probably set a change hook on the net-profit field so that when its value changed, the record could be redisplayed in the appropriate format automatically. Here is an example of how to change the data display format in response to a particular field being changed. @lisp (defun equip-dbf-from-field (fieldname oldval newval) (let ((dbf-elt (assoc newval dbf-format-name-spec-alist)) (save-index dbf-this-field-index)) (db-change-format (if dbf-elt newval "default")) (setq dbf-this-field-index save-index) ; otherwise aref on nil ;; redisplay record t)) (setq db-after-read-hooks (lambda () (dbf-set-change-function 'equip-type 'equip-dbf-from-field))) @end lisp @node Edit mode hooks @subsection Edit mode hooks @cindex edit mode hooks @cindex hooks, edit mode These hooks are called whenever you enter a field to edit it, which provides an easy way to customize the behavior of particular format fields. @defvar dbf-enter-field-hook Normal hook run whenever a display field is entered. The displayspec index is @code{dbf-this-field-index}. @end defvar Note: For a @code{.edb} file (when using @code{edb-interact}), use the technique described in @ref{Database mode hooks}. It is sometimes advantageous to have a particular action happen only once per edit of a record. For instance, when a record's address, city, state, or zip-code fields are edited, we might like to copy all the values to the old-address, old-city, old-state, and old-zip-code fields. We only want this to happen once, however: if you edit first the address, then the city, we don't want to repeat the process, because then the old-address field would get written over by the new value of the address field. One way to prevent this from happening more than once is to set a variable when the copying is done, and then don't do the copying if that variable is set. The variable would be reset whenever a new record was edited. You can use @code{db-edit-mode-hooks} to do this job. @lisp (setq db-after-read-hooks (lambda () (set (make-local-variable 'db-edit-mode-hooks) (lambda () (dolist (var '(tep-homeaddr-oldified tep-homephone-oldified tep-bizaddr-oldified tep-bizphone-oldified)) (set (make-local-variable var) nil)))) (dbf-set-change-function 'home-phone 'tep-homephone-change-hook) (setq db-after-read-hooks nil))) (defvar tep-homephone-oldified nil) (defun tep-homephone-change-hook (fieldname oldval newval) (unless tep-homephone-oldified (dbf-this-record-set-field 'old-home-phone oldval)) ;; non-nil return value means redisplay whole record (prog1 (not tep-homephone-oldified) (setq tep-homephone-oldified t))) @end lisp @node Display format change hooks @subsection Display format change hooks @cindex display format change hooks @cindex change hooks, for display formats @cindex hooks, change, for display formats The following hook is run whenever a new record is created. This hook is set automatically when the control property @code{:record-defaults} is specified (@pxref{Control properties reference}). @defvar db-new-record-function Function called on empty records before they're inserted in the database. Takes two arguments, the record and the database. @end defvar @cindex new records, setting default information A typical use is to set default information or add a timestamp. For instance: @lisp (defun set-update-date (record database) "Provide defaults for new records in the database." (db-record-set-field record 'updatedate (edb-t-timedate1:parse-date-string (current-date)) database)) (setq db-new-record-function 'set-update-date) @end lisp The display format change hooks are called when you change a record field value. There are separate change hooks that run the first time any field is modified, whenever any field is modified, and whenever a particular field is modified. They run in the order @code{dbf-first-change-function}, @code{dbf-every-change-function}, and finally one of the elements set by @code{dbf-set-change-function}. Each change hook is either @code{nil} or a function of three variables: the fieldname of the just-modified field (a symbol) and the pre- and post-modification field values. These functions can set variable @code{dbf-redisplay-entire-record-p} to a non-@code{nil} value in order to cause the entire record to be redisplayed (for instance, if the change hook modifies fields other than that named by its first argument). @vindex dbf-redisplay-entire-record-p @defvar dbf-first-change-function A function called the first time a record field is modified, or @code{nil}. The function takes the fieldname and the old and new values as arguments, and returns @code{t} if the record should be redisplayed. This variable is set automatically when the control property @code{:first-change-function} is specified (@pxref{Control properties reference}). @end defvar @cindex last modification field Here is an example of code to update the last modification field of a record, assuming its type is date: @lisp (defun update-last-modified-date (fieldname oldval newval) "Put the current date in this record's `last modified' field." (dbf-this-record-set-field 'last-modified (edb-t-timedate1:parse-date-string (current-date)))) (setq dbf-first-change-function 'update-last-modified-date) @end lisp @defvar dbf-every-change-function A function called whenever a record field is modified, or @code{nil}. The function takes the fieldname and the old and new values as arguments, and returns @code{t} if the record should be redisplayed. This variable is set automatically when the control property @code{:every-change-function} is specified (@pxref{Control properties reference}). @end defvar @defun dbf-set-change-function fieldname function Set the change function for @var{fieldname} to @var{function} in the current database. @var{function} takes the fieldname and the old and new values as arguments, and returns @code{t} if the record should be redisplayed. @end defun @cindex dependent field values It is easy to make a field's value dependent on that of another field. For instance, suppose a salesman's commission should be 10% of the selling price of an item, and both fields are of type number. You could make the commission field unreachable (@pxref{Display specification optional parameters}) and compute it whenever the selling price field varies. The latter operation could be done as follows: @lisp (defun set-commission (fieldname oldval newval) (dbf-displayed-record-set-field 'commission (/ newval 10))) (dbf-set-change-function 'selling-price 'set-commission) @end lisp There are two things to notice about this example. First, we need not set @code{dbf-redisplay-entire-record-p}, as @code{dbf-displayed-record-set-field} does that automatically. Second, if we replaced @code{newval} by @code{(dbf-displayed-record-field 'selling-price)}, then the function would work even if not called as a change function for selling-price. You may modify records explicitly by calling @code{dbf-displayed-record-set-field} (@pxref{Manipulating records}); when that is done, the following hook is invoked. It is different from the above functions in that they are called when you edit a field, while it is called when Emacs Lisp code modifies a field (usually as a result of some interactive command). @defvar dbf-set-this-record-modified-function A function called when the current record is marked as modified. The function takes no arguments and its return value is ignored. It is called after the original record values are copied to the working record. @end defvar Another function is invoked when changes to a record are committed --- that is, when changes to the record which is being displayed are copied back into its original in the database. @defvar dbf-after-record-change-function Function called whenever changes to a record are recorded semi-permanently. The function takes the record as an argument. Its return value is ignored. @end defvar Note: To achieve the same effect as setting these two variables for a @code{.edb} file (when using @code{edb-interact}), use the technique described in @ref{Database mode hooks}. @node Global variables @section Global variables @cindex customization, global variables This section describes some customization variables which you can use to understand and (if lucky) control EDB's behavior. When a potentially slow computation is underway, EDB displays a message in the echo area reporting how many records have been processed. Use the following variable to control how often this message is updated. @defvar db-inform-interval When doing a lengthy computation, display a progress message in the echo area every this many records. If @code{nil}, don't inform. @end defvar Note: For a @code{.edb} file (when using @code{edb-interact}), use the technique described in @ref{Database mode hooks}. @node Database representation @chapter Database representation @cindex database representation @cindex representation of database Perhaps the most important information about a database --- besides the records it contains --- is the number of fields in each record, and the type of each field. As explained previously (@pxref{Terminology and concepts}), a database consists of records with identical numbers of fields; each field has an associated type such as string or integer. Each field also has a name which is used when extracting its value from the record. Internally, records and metainfo about them (individually and in aggregate) are represented by various vectors and hash tables; however, you should never manipulate those structures directly, only through the functions described in this chapter. @defvar dbc-database This is a buffer-local variable that contains the @dfn{current database}. @end defvar Given a record, it is not possible to determine which database (if any) it belongs to. The database-to-record connection is one-way. @menu * Mapping over the database:: * Manipulating records:: @end menu @node Mapping over the database @section Mapping over the database @cindex mapping over the database @cindex looping over the database Mapping refers to applying a function to each record in the database, or executing a piece of code for each record. @defun db-maprecords func [database [hide [message [accumulate]]]] Apply @var{func} to every record in the current database in order of ascending index. Optional second arg @var{db} specifies a database to use other than the current one. If optional third arg @var{hide} is non-@code{nil}, apply @var{func} only to unhidden records. If optional fourth arg @var{message} is non-@code{nil}, it should be a format string containing one numeric (%d) specifier. That message will be issued every @code{db-inform-interval} records. If optional fifth arg @var{accumulate} is non-@code{nil}, return a list of the results; otherwise return @code{nil}. @end defun There is also the alias @code{maprecords} for old code. (If you can help it, use @code{db-maprecords} instead.) For instance, to sum, for all records, the values contained in field @samp{summand} (of type @code{number}), you could use either of the following forms: @lisp (let ((result 0)) (db-maprecords (lambda (record) (setq result (+ result (db-record-field record 'summand))))) result) (apply (function +) (db-maprecords (lambda (record) (db-record-field record 'summand)) nil nil nil t)) @end lisp @node Manipulating records @section Manipulating records @cindex record representation A database consists of records, each of which has the same makeup: corresponding fields in a database's records contain data of the same type. For instance, the fifth field of each record might contain an address, and the seventh field, a date. The particular addresses and dates would would vary from record to record. (Different databases will contain records with different numbers and types of fields.) Each field has a name and a type, which specifies what sort of information can be stored in the field; for more details about record field types, @xref{Record field types}. Records are represented internally as vectors, but should never be operated on as such; use the abstractions described in this section. @subsection Creating and copying records @cindex creating records @cindex copying records @defun db-make-record database init Return a @var{database}-specific record initialized with @var{init}. @var{init} is either a list of alternating field names (symbols) and values, or a list whose car is the keyword @code{:alist} and whose cdr is an alist mapping field names to their values. @end defun When you create a new record by using @code{db-add-record} (@pxref{Adding and removing records}), @code{db-new-record-function} is invoked (@pxref{Display format change hooks}), the number of records in the database is modified, and so forth. @code{db-make-record}, on the other hand, performs none of these housekeeping tasks. @subsection Accessing record fields @cindex accessing record fields @cindex setting record fields @cindex reading record fields @cindex record fields, accessing @cindex fields, accessing them in records @cindex fields, setting them in records @cindex fields, reading them in records Ordinarily, record fields are accessed by specifying the name of the desired field; the database must also be specified so that the fieldname-to-fieldnumber correspondence can be determined. @defun db-record-field record fieldname [database] Return from @var{record} the field with name @var{fieldname}. If @var{record} is t, use the ``current record''. Optional third argument @var{database} specifies a database other than the current one. @end defun @defun db-record-set-field record fieldname value [database [nocheck]] Set, in @var{record}, field @var{fieldname} to @var{value}. Fourth argument is @var{database}. Check constraints first unless optional fifth argument @var{nocheck} is non-@code{nil}. @end defun There are also special commands for manipulating the current record --- that is, the one that appears in the data display buffer. These functions require fewer arguments, flag that a redisplay of the record is necessary, and automatically call @code{dbf-set-this-record-modified-p}, which is essential if the changes are to be copied back into the original record in the database from the one that is being displayed. (A copy is always displayed so that changes can be undone.) @defun dbf-displayed-record Return the record currently displayed in this data display buffer. This may either be the working copy, if the record has been marked as modified, or the original otherwise. @end defun @defun dbf-displayed-record-field fieldname Return the value of the field named @var{fieldname} from the displayed record. @end defun @defun dbf-displayed-record-set-field fieldname value Set field with name @var{fieldname} in displayed record to @var{value}. Cause the entire record to be redisplayed soon. @end defun @defun dbf-displayed-record-set-field-and-redisplay fieldname value Set field with name @var{fieldname} in displayed record to @var{value}. Cause the entire record to be redisplayed immediately. @end defun @defun dbf-set-this-record-modified-p arg Mark the current record as modified if @var{arg} is non-@code{nil}. If the record was previously not marked as modified, make a copy of the original, and call @code{dbf-set-this-record-modified-function}. @end defun @node Naming conventions @chapter Naming conventions @cindex naming conventions EDB makes use of several namespaces: Emacs lisp functions and variables, file names, and type names. To reduce confusion, names have been chosen following some conventions, described in this chapter. @section Function and variable naming conventions @cindex function naming conventions @cindex variable naming conventions Functions and variables begin with one of the following prefixes. @table @code @item edb-t-GROUP: Functions or variables supporting some @dfn{type group} (for lack of a better name). Note the trailing @kbd{:}. The type names themselves do not presently follow any conventions, although that may change in the future with EDB 2.x. @item edb- Data structures and functions related to the (meta) binding behavior. Many of these have two hyphens instead of one, which means the item is @dfn{internal} in some sense; its definition may change without warning from one EDB release to the next. @item db- In a variable, indicates that the variable is global and affects all databases. It is also used in some situations for internal database functionality which is not connected with any particular buffer. @item database- These functions operate on (the internal representation of) the database structure itself. @item dbc- Indicates a variable local to the data display buffer which refers to the current database (the database being manipulated by that data display buffer). The `c' stands for ``current.'' @item dbf- Indicates a variable local to the data display buffer which controls some aspect of formatting. The `f' stands for ``format''; many such variables are intimately related to the format, and the data display buffer used to be called the format buffer. @item dbs- Indicates a variable local to the summary buffer, or a summary buffer function. Since the summary buffer may disappear at any time, the summary buffer gets most of its information from the associated data display buffer's local variables. @item dbsi- Indicates a variable local to a sort interface buffer, or a sort interface function. @end table @section File naming conventions @cindex file naming conventions By convention, database file names contain one of the following suffixes: @table @code @item edb-t-GROUP.el Contains forms that implement a type group (see above). @item .dat These are database files proper; they contain the information that makes up the fields and records of the database. Database filenames may also contain no extension at all. @item .fmt Format files control the structure of the data display buffer, which displays one record at a time. @item .dba Auxiliary files contain arbitrary Emacs Lisp code; they can be used to define functions, set variables, or operate directly on the database. @end table Other suffixes --- or none at all --- can be easily used; for instance, see variables @code{db-format-file-suffixes} and @code{db-aux-file-suffixes} (@pxref{Auxiliary files}). For more information, @xref{Invoking EDB}. @section Type naming conventions @cindex type naming conventions There is only one minor naming convention for types: @code{BASE-or-nil} usually means that handling for the type is very similar to handling for type @var{base} with special handling in case the value is @code{nil}. @node In case of trouble @chapter In case of trouble @section Variables @cindex variable documentation missing @cindex variable default value missing @cindex trouble with undefined variables In some cases the documentation strings and/or default values of some variables may be missing --- as if the variables were not yet defined. That's because the variables are not yet defined; they are associated with part of EDB which hasn't been loaded because it hasn't been needed yet. The documentation and default values will appear when that part of EDB is loaded (if you set such variables, your values will not be replaced). Such variables are correctly declared buffer-local (if appropriate), so you can set them without fear of the changes affecting other buffers. @section Exiting Emacs or saving files @cindex exiting Emacs, trouble with @cindex trouble with exiting Emacs @cindex saving files, trouble with @cindex trouble with saving files If you are unable to exit Emacs or to execute @code{db-save-some-buffers} because Emacs is trying to manipulate a database which doesn't exist or because an EDB bug is triggered by the attempt to save an existing database, you can set variable @code{edb--global-state} to nil and reload @file{edbcore.elc}. [TODO: Write a reset command; document it here. --ttn] This indicates to EDB that there are no databases read into memory and, therefore, no operations will be attempted on them as a part of saving all modified Emacs buffers. @findex db-save-some-buffers @section Poking Around If things get really weird, you can try to use the command @code{edb-meta} and include the result in a bug report to the EDB maintainer. @defun edb-meta Summarize EDB state in a new buffer, and switch to it. The output format is likely to change from one release of EDB to the next; do not rely on it. @end defun @node Function Index @unnumbered Function Index @printindex fn @node Variable Index @unnumbered Variable Index @printindex vr @node Concept Index @unnumbered Concept Index @printindex cp @c To prevent the Concept Index's last page from being numbered "i". @page @summarycontents @contents @bye edb-1.31/doc/refcard.tex0000444000175000017500000002030510745370011013255 0ustar ttnttn% refcard.tex % % Copyright (C) 2007 Erich W\"alde % % Permission is granted to make and distribute verbatim copies of % this refcard provided the copyright notice and this permission notice % are preserved on all copies. % % Permission is granted to copy and distribute modified versions of % this refcard under the conditions for verbatim copying, provided that % the entire resulting derived work is distributed under the terms of a % permission notice identical to this one. % % Permission is granted to copy and distribute translations of this % manual into another language, under the above conditions for modified % versions, except that this permission notice may be stated in a % translation approved by the Free Software Foundation. \documentclass[a4paper,landscape]{article} \usepackage[latin1]{inputenc} \usepackage[hmargin=8mm,vmarginratio=1:1,top=16mm]{geometry} \usepackage{multicol} \pagestyle{empty} \columnsep 14mm \columnseprule 0.4pt \def\author{Erich W\"alde} \input refcard.version.tex \def\version{\versionnumber\ --- \updated} \def\shortcopyrightnotice{\centerline{\small Copyright \copyright\ \year\ \author}} \def\copyrightnotice{\vskip 1ex plus 2 fill \shortcopyrightnotice {\tiny Permission is granted to make and distribute verbatim copies of this refcard provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this refcard under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. \par}} % we won't be using math mode much, so redefine some of the characters % we might want to talk about \catcode`\^=12 \catcode`\_=12 \chardef\\=`\\ \chardef\{=`\{ \chardef\}=`\} \hyphenation{mini-buf-fer} \parindent 0pt %\parskip 1ex plus .5ex minus .5ex % title - page title. Argument is title text. \outer\def\title#1{{\huge\centerline{\sc{#1}}}\vskip 1ex plus .5ex} % section - new major section. Argument is section name. \outer\def\section#1{\par\filbreak \vskip 3ex plus 2ex minus 2ex \centerline{\large\bf #1}\mark{#1}% \vskip 2ex plus 1ex minus 1.5ex} % kbd - argument is characters typed literally. Like the Texinfo command. \def\kbd#1{{\tt#1}\null} %\null so not an abbrev even if period follows % key - definition of a key. % \key{description of key}{key-name} % prints the description left-justified, and the key-name in a \kbd % form near the right margin. \def\key#1#2{\leavevmode\hbox to \hsize{\vtop {\hsize=.80\hsize\rightskip=1em \relax#1}\kbd{#2}\hfil}} % prop - control file properties \def\prop#1#2{\kbd{#1} {\it#2}\vskip 0mm} \newbox\metaxbox \setbox\metaxbox\hbox{\kbd{M-x }} \newdimen\metaxwidth \metaxwidth=\wd\metaxbox % metax - definition of a M-x command. % \metax{description of command}{M-x command-name} % Tries to justify the beginning of the command name at the same place % as \key starts the key name. (The "M-x " sticks out to the left.) \def\metax#1#2{\leavevmode\hbox to \hsize{\hbox to .80\hsize {\relax#1\hfil}% \hskip -\metaxwidth minus 1fil \kbd{#2}\hfil}} % dsopt - like key and metax for displayspec options \def\dsopt#1#2{\leavevmode\hbox to \hsize{\hbox to .45\hsize {\relax\kbd{#1}\hfil}% \hskip -\metaxwidth minus 1fil #2\hfil}} %**end of header \begin{document} \begin{multicols}{3} \title{EDB Reference Card} \centerline{(for EDB \version)} \shortcopyrightnotice \small \section{control file properties} \prop{:display}{text-block-spec} \prop{:fields}{vector} \prop{:tagged-setup}{plist} \prop{:read-record}{function} \prop{:write-record}{function} \prop{:record-separator-function}{function} \prop{:record-terminator}{string-or-regexp-vector} \prop{:record-separator}{string-or-regexp-vector} \prop{:field-separator}{string-or-regexp-vector} \prop{:substitution-separators}{[fsep rsep]} \prop{:substitutions}{vector} \prop{:cruft}{[[befrec aftrec] [beffld aftfld]]} \prop{:data}{text-block-spec} \prop{:choose-display}{function} \prop{:before-display}{function} \prop{:report}{text-block-spec} \prop{:summary-format}{string} \prop{:name}{string} \prop{:first-change-function}{function} \prop{:every-change-function}{function} \prop{:field-order}{vector} \prop{:locals}{vector} \prop{:record-defaults}{function} \section{displayspec options} \dsopt{width=$N$}{maximum field width (space chars)} \dsopt{height=$N$}{maximum field height (lines)} \dsopt{right-justify}{pad with spaces on the left} \dsopt{reachable}{editable field} \dsopt{unreachable}{read-only field} \section{builtin types} displayspecs: \kbd{ integer integer-or-nil number number-or-nil yes-no string one-line-string string-or-nil nil-or-string one-line-string-or-nil } \par recordfieldtypes: \kbd{ integer integer-or-nil number number-or-nil boolean string one-line-string string-or-nil nil-or-string one-line-string-or-nil } \par \section{entering/leaving database mode} \metax{connect via control (\kbd{.edb}) file}{M-x edb-interact} \metax{read a database file (old way)}{M-x db-find-file} \key{save the database file to disk}{C-x C-s} \key{save the database file to disk}{C-x C-w} \key{quit editing for now (bury buffers)}{q} \key{exit edb buffers, prompt to save changes}{x} \section{in view mode} \key{go to next record}{n} \key{go to previous record}{p} \key{go to first record}{<, M-<} \key{go to last record}{>, M->} \key{jump to record {\tt N}}{C-u N j} \key{go to next screen or record}{SPC} \key{go to previous screen or record}{DEL} \key{go to first field and switch to edit mode}{TAB, C-n, e} \key{go to last field and switch to edit mode}{M-TAB, C-p} \key{see a summary of all records}{D, H, h} \key{invoke sort interface}{S} \key{commit current record to database}{RET} \key{undo all changes since entering the record}{C-x u} \key{undo all changes since last saving of database}{C-x r} \key{add a new record just before current one}{a, i} \key{copy current record and go to the copy}{c} \key{output current record to another database}{o} \key{delete current record}{d, k} \key{yank most recently-deleted record}{y} \key{generate report}{r} \key{set summary format}{F} \key{toggle {\tt truncate-lines}}{t} \key{new data display buffer}{+} \section{in edit mode} \key{return to view--mode}{C-c C-c} \key{undo changes to current field}{C-x U} \key{go to next field}{TAB} \key{go to previous field}{M-TAB} \key{go to first field}{M-<} \key{go to last field}{M->} \key{go to next line or field}{C-n} \key{go to previous line or field}{C-p} \key{display help for current field in echo area}{M-?} \key{search for a value in the current field}{M-s} \section{sort interface} \metax{enter the sort interface}{M-x db-sort} \key{toggle hidden-to-end}{t} \key{kill line and add to kill stack}{C-k} \key{yank lines from kill stack}{C-y} \key{increasing sort order}{i} \key{decreasing sort order}{d} \key{increase priority of field at point}{M-p} \key{decrease priority of field at point}{M-n} \key{specify an ordering function}{o} \key{specify a sorting function}{s} \key{use current ordering, make db default}{RET, C-c C-c} \key{use current ordering, make buffer default}{A, U} \key{use current ordering for this sort only}{a, u} \key{sort according to field at point}{!} \key{abort sort}{q} \key{clear sort order and exit without sorting}{c} \section{marking and hiding} \key{toggle record marked/unmarked}{m} \key{toggle record hidden/unhidden}{O} \metax{hide all unmarked records, clear marks}{} \metax{}{db-hide-unmarked-records} \metax{mark all unhidden records, clear hide bits}{} \metax{}{db-mark-unhidden-records} \metax{clear all marks}{db-unmark-all} \metax{clear all hide bits}{db-unhide-all} \key{goto next record, even if hidden}{M-n} \key{goto previous record, even if hidden}{M-p} \key{goto next marked record}{M-C-n} \key{goto previous marked record}{M-C-p} \metax{enable/disable hiding}{dbc-set-hide-p} \key{toggle whether hiding is in effect}{M-o} \key{toggle show hidden in summary}{M-C-o} \parindent 5mm \vskip 10mm \copyrightnotice \end{multicols} \end{document} % refcard.tex ends here edb-1.31/AUTHORS0000444000175000017500000000472010745370011011433 0ustar ttnttnThien-Thi Nguyen: in subdir `lisp', wrote: system.el state.el connection.el edb-1int-to-single.el edb-meta.el in subdir `examples', wrote: arb-demo-regexp.edb arb-demo.edb eicsw.edb forms-demo2-inherent.edb forms-demo2.edb geneal.edb names.edb null.edb passwd.edb rolo-jik.edb www-links www-links.edb www-links2 www-links2.edb www-links3 www-links3.edb in subdir `skram', wrote everything; changed almost everything else, as well Alan K. Stebbens: in this directory wrote: db-rdb.el edb-t-places-usuk.el edb-t-timedate1.el in this directory changed: db-time.el Bertrand Petit: in this directory wrote: db-isbn.el db-isbntst.el Jonathan I. Kamens: in subdir `examples' wrote: rolo-jik.dat rolo-jik.dba rolo-jik.doc rolo-jik.fmt Michael A. Patton: in this directory wrote: db-tagged.el in subdir `examples' wrote: geneal geneal.dat Michael Burschik: in subdir `examples/edbibtex' wrote: article.fmt bibtex.dba bibtex.fmt book.fmt booklet.fmt compile.el edbibtex.el edbibtex.texinfo inbook.fmt incollection.fmt inproceedings.fmt manual.fmt mastersthesis.fmt misc.fmt phdthesis.fmt preamble.fmt proceedings.fmt string.fmt techreport.fmt unpublished.fmt Michael Ernst: in this directory wrote: database.el db-interfa.el db-rep.el db-util.el db-convert.el db-search.el db-time.el edb-t-human-names.el db-file-io.el db-sort.el db-two-dbs.el edb-t-places-usuk.el db-format.el db-summary.el db-types.el edb-t-timedate1.el in subdir `examples' wrote: arb-demo arb-demo-regexp arb-demo-regexp.dba arb-demo.dba arb-demo.fmt arb-demo.home-fmt eicsw.dat eicsw.dba eicsw.fmt forms-demo2.dat forms-demo2.fmt forms-demo2.report names.dat names.fmt tepdb tepdb.dba tepdb.fmt tepdb.instr in this directory changed: db-isbn.el db-isbntst.el db-rdb.el db-tagged.el R. J. Chassell: in subdir `examples' wrote: intro-and-addr Thorsten Ohl: in subdir `examples/btxdb' wrote: article.fmt bibtex.fmt book.fmt booklet.fmt btxdb.el btxdb.texi conference.fmt inbook.fmt incollection.fmt inproceedings.fmt journals-abbrev.rep journals-full.rep journals.dat journals.dba journals.fmt manual.fmt mastersthesis.fmt misc.fmt phdthesis.fmt proceedings.fmt techreport.fmt unpublished.fmt in subdir `examples/btxdb/examples' wrote: bibtex.bib Erich Waelde: in subdir `doc' wrote: refcard.tex edb-1.31/BUGS0000444000175000017500000004424511016261153011052 0ustar ttnttnBUGS known to infest EDB (at some point). Please send bug reports not covered in this file to . Include version (from `M-x edb-version'), a snapshot of the *Database Log* and *Backtrace* buffers (if available), the smallest possible set of files to reproduce the bug, a description of the precise actions that triggered the bug (starting from "emacs -q"), your observations of the actual events, and a description of what you expected to see. The following is to remind the EDB maintainer what means what (ignorable): HEADER MEANING Id serial number of the bug Summary one-line description of the buggy behavior Status one of: unresolved, fix-applied, resolved Reported-Version released version of EDB that demonstrates this bug Reported-By either "ttn" or the someone's email address Reported-Date when reported (and hopefully entered into BUGS :-) Fix-Applied-Summary one-line description of the fix Fix-Applied-Date when status changed to fix-applied Fix-Applied-Version version at and after which no longer demonstrate the bug Resolved-Date when status changed to resolved Here is an example record: Id: 0 Summary: No BUGS file Status: resolved Reported-Version: 1.23 Reported-By: ttn Reported-Date: 2004-10-12 Fix-Applied-Summary: Write a BUGS file Fix-Applied-Date: 2004-10-12 Fix-Applied-Version: 1.24 Resolved-Date: 2004-10-12 It's unknown whether projects w/ a BUGS file accumulate more or less bugs than those w/o. EDB can be used to fan these speculative embers -- cool! Id: 1 Summary: EDB cannot manipulate the BUGS file as a database Status: resolved Reported-Version: 1.24 Reported-By: ttn Reported-Date: 2004-10-13 Fix-Applied-Summary: Stash regexp-matched text on read for later write. Fix-Applied-Date: 2007-12-27 Fix-Applied-Version: 1.28p2 Resolved-Date: 2007-12-27 2004-10-13 At the moment, everything is missing: schema, display format(s), integration w/ maintenance methodology (e.g., "make check"), etc. 2007-05-28 Looks like BUGS.edb works for reading. Writing still loses. Also, no way to update ChangeLog, no "make check" integration, etc. 2007-12-27 Writing succeeds (if the file is writeable :-). Id: 2 Summary: Function and variable names conflict w/ the rest of Emacs Status: unresolved Reported-Version: 1.24 Reported-By: ttn Reported-Date: 2004-10-13 Most things have been pushed into `db-', `database-' or `db[a-z]*-'. However, there are still quite a few exceptions, notably functions and vars in db-time.el (e.g., `parse-time-string') and in db-types.el (e.g., `abbreviate-state'). The latter is more of a latent conflict than an immediately pressing one. [Insert standard Emacs-single-namespace-is-a-PITA lament, here.] Id: 3 Summary: Build failure Status: resolved Reported-Version: 1.23 Reported-By: jsbien@mimuw.edu.pl Reported-Date: 2004-09-25 Fix-Applied-Summary: Use `default-directory' in `load-path' when compiling Fix-Applied-Date: 2004-10-13 Fix-Applied-Version: 1.24 Resolved-Date: 2008-01-16 The bug report said that db-nosetf.el was not able to be loaded. Now function `edb-byte-compile-all' unconditionally adds `default-directory' to `load-path'. 2008-01-16 ttn sez: no further activity, marking "resolved". Id: 4 Summary: Invoking `db-next-field' in data display buffer throws error Status: unresolved Reported-Version: 1.24 Reported-By: ttn Reported-Date: 2004-10-13 In the data display buffer, command `M-x db-next-field' throws a "Wrong type argument: integer-or-marker-p, nil" error since "current-field" state has not yet been initialized (by calling `db-first-field', typically bound to TAB). This bug is just one of many in a family. The whole current-field tracking and attributes-setting is extremely cumbersome; too many independent variables requiring too much stylized access/mutation. Fix requires rethought/redesign using a more scalable approach based on model-view-controller and some kind of observer protocol. A kludge that was tried, and subsequently reverted, was to add: (unless dbf-this-field-beginning-pos (db-first-field) (setq arg 0)) to the beginning of `db-next-field'. This worked for a bit but resulted in other errors later for other commands and then also later for `db-next-field' itself. Id: 5 Summary: Command db-save-database signals "Wrong type argument" error Status: resolved Reported-Version: 1.24 Reported-By: nr-tkz@nifty.com Reported-Date: 2004-11-20 Fix-Applied-Summary: Fix typo in db-rep.el introduced in EDB 1.23 Fix-Applied-Date: 2005-01-12 Fix-Applied-Version: 1.25 Resolved-Date: 2008-01-16 > EDB 1.24 fails to save database when I execute db-save-database for > the first time after modifying it. But when I execute db-save-database > again, no error occurs and EDB successfully saves the database. The > error message reads as follows: > > database-set-modified-p: Wrong type argument: arrayp, nil > > The problem seems to be the argument passed to > database-clean-data-display-buffers in database-set-modified-p, but I > am unable to further look into the problem. > > EDB 1.23 does not cause this error. I send you sample database and > format files. I am using GNU Emacs 21.3.50.1 (i386-mingw-nt5.0.2195) > of 2004-11-02 on MS Windows. ttn: > there was a typo in db-rep.el introduced in all the mad refactoring. > the following patch fixes it. > > diff -w -b -B -u --unified=1 -r1.58 -r1.60 > --- db-rep.el 13 Oct 2004 16:27:34 -0000 1.58 > +++ db-rep.el 12 Jan 2005 01:56:05 -0000 1.60 > @@ -101,3 +100,3 @@ > (force-mode-line-update))) > - (database-clean-data-display-buffers database)))) > + (database-clean-data-display-buffers db)))) 2008-01-16 ttn: no further activity, marking "resolved". Id: 6 Summary: Data file coding system not autodetected Status: resolved Reported-Version: 1.24 Reported-By: nr-tkz@nifty.com Reported-Date: 2004-11-19 Fix-Applied-Summary: Honor new buffer-local var `edb-coding-system' Fix-Applied-Date: 2005-01-14 Fix-Applied-Version: 1.25 Resolved-Date: 2008-01-16 > I am using EDB 1.24 but it fails to read some database files properly > showing the following message: Database file is improperly formatted: > try to read it anyway? If I answer yes, it reads database but all > records get garbled. This happens when I deal with database files > encoded in utf-16le which apparently have no problem. > > Since Emacs fails to autodetect the coding system of these files when > I let it read them using the find-file command without specifying the > coding system, it looks like EDB simply fails to autodetect the coding > system when showing the above message. > > I wonder if there is some way to specify the coding system of database > files when I execute the db-find-file command. I tried the > universal-coding-system-argument command but it did not work. > > I send you sample database and format files (the database file > contains some Japanese and French accented characters) along with the > database log. I am using GNU Emacs 21.3.50.1 (i386-mingw-nt5.0.2195) > of 2004-11-02 on MS Windows. ttn: > a temporary workaround: > > (add-to-list 'auto-coding-alist '(".../sample.dat" . utf-16le)) > (db-find-file ".../sample.dat") ttn 2005-01-14 00:29:30: > i've added support (and slight documentation) for new buffer-local var > `edb-coding-system'. 1.x compatability constrains this support, > however, so that it does not work for all internal layout data files > (further discussion in bug #7). ttn 2008-01-16 15:14:20: no further activity, marking "resolved". Id: 7 Summary: Internal layout data w/ unrecognized encoding causes problems Status: unresolved Reported-Version: 1.25 Reported-By: ttn Reported-Date: 2005-01-14 if we have the following scenario: - data file is in internal layout format (schema and data together); and - data file encoding is not automatically recognized by Emacs; then the conventional method of using `universal-coding-system-argument' (C-x RET c) before the I/O operation (in this case `db-find-file') only works in cases where either: - there is no format file (very uncommon in the above scenario); or - the format file encoding is the same as for the data file. a large part of the problem lies in function `db-read-database-file' which does not properly modularize (i.e., kludgily special cases) internal layout format data file reading. unfortunately, the precise sequence of events required for database access and EDB state init has been documented as part of the public interface and thus is not fungible, if EDB 1.x compatability is to be taken as an uncompromising requirement. matters are complicated by the fact that multiple I/O operations are done, proving the "internal" format not so well encapsulated as one might prefer. Id: 8 Summary: Sorting in reverse incorrectly handles (eq obj1 obj2) Status: resolved Reported-Version: 1.21 Reported-By: ew.ng116837@online.de Reported-Date: 2005-01-15 Fix-Applied-Summary: Maintain arg order and invert the result Fix-Applied-Date: 2005-01-17 Fix-Applied-Version: 1.25 Resolved-Date: 2005-01-24 When obj1 and obj2 are not "equal", to effect "reverse sort" it is enough to invert the order of the arguments to the ordering function. However, this fails when obj1 and obj2 are "equal"; in that case, the return value does not indicate "reverse" (loses the inversion property). WRONG: (lambda (obj1 obj2) (funcall ORDFUNC obj2 obj1)) TESTS: assume ORDFUNC is `<' obj1 obj2 result 1 2 nil OK 2 1 t OK 3 3 nil WRONG The fix is to invert the result of the ordering function unconditionally, and take care to not disturb the order of the args passed to the ordering function. RIGHT: (lambda (obj1 obj2) (not (funcall ORDFUNC obj1 obj2))) TESTS: assume ORDFUNC is `<' obj1 obj2 result 1 2 nil OK 2 1 t OK 3 3 t OK Incidentally, this bugfix was part of some "EDB 1.21 Fixes" micro package floating around tHe net, necessitated by many years of EDB maintainer unresponsiveness. Id: 9 Summary: Creation method canonicalization inconsistent Status: resolved Reported-Version: 1.21 Reported-By: ew.ng116837@online.de Reported-Date: 2005-01-15 Fix-Applied-Summary: Make db-canonicalize-creation-method return a list Fix-Applied-Date: 2005-01-17 Fix-Applied-Version: 1.25 Resolved-Date: 2005-01-24 Caller expects a list, callee used to return a cons. (Pretty ironic for a function w/ "canonicalize" in its name.) It now returns a list. Incidentally, this bugfix was part of some "EDB 1.21 Fixes" micro package floating around the net, necessitated by many years of EDB maintainer unresponsiveness. Id: 10 Summary: Function `locate-file' not defined Status: resolved Reported-Version: 1.24 Reported-By: ew.ng116837@online.de Reported-Date: 2005-01-15 Fix-Applied-Summary: Raise caller abstraction and rewrite to not use it Fix-Applied-Date: 2005-01-18 Fix-Applied-Version: 1.25 Resolved-Date: 2005-01-24 The function `locate-file' is provided in GNU Emacs in cvs, and is thus not widely available. The fix is to raise the abstraction level for callers to new func `db-locate-readable-file-prefer-cwd'. This bug was introduced in EDB 1.24 during the mad refactoring. Light testing was done on stock install of GNU Emacs 21.2, which does not provide `locate-file'. Id: 11 Summary: Missing support for "make edb.dvi" Status: resolved Reported-Version: 1.24 Reported-By: ew.ng116837@online.de Reported-Date: 2005-01-18 Fix-Applied-Summary: Add it back Fix-Applied-Date: 2005-01-19 Fix-Applied-Version: 1.25 Resolved-Date: 2005-01-24 This support was dropped in the re-org for EDB versions 1.22 through 1.24. Sorry about that. --ttn Id: 12 Summary: Displayspec with multiple options mis-handled Status: resolved Reported-Version: 1.27 Reported-By: ttn Reported-Date: 2007-04-28 Fix-Applied-Summary: Make displayspec parsing more robust Fix-Applied-Date: 2007-04-30 Fix-Applied-Version: 1.27p2 Resolved-Date: 2007-04-30 The displayspec `\id,width=5,right-justify' renders the field `id' without any padding whatsoever. This is due to two bugs: (1) handling of right-justify does not set a proper "padding action" function; (2) parsing recognizes only the last option when given multiple options. To fix (1), a new (revived old) func `db-pad-left' was created and the entry for `right-justify' in `db-optspec-list' modified to return it. For (2), the following analysis illustrates the underlying problem: (defun test (rx) (let ((s "\\x,y,z")) (when (string-match rx s) (mapcar (lambda (n) (cons n (match-string n s))) '(0 1))))) (test "\\\\x\\(,y,z\\)") ; A ((0 . "\\x,y,z") (1 . ",y,z")) (test "\\\\x\\(,[yz],[yz]\\)") ; B ((0 . "\\x,y,z") (1 . ",y,z")) (test "\\\\x\\(,[yz],[yz]\\)*") ; C ((0 . "\\x,y,z") (1 . ",y,z")) (test "\\\\x\\(,[yz]\\)*") ; D ((0 . "\\x,y,z") (1 . ",z")) We see that all matches [A-D]0 yield the entire input string. Fine. However, matches [ABC]1 all yield ",y,z" but match D1, which happens to be the approach used in the parsing code, does not. To fix (2), we rework the regexp to be, essentially, "\\\\[xyz,]*"; that is, combining the initial element w/ the options and including the delimiter (comma). Then `split-string' on "," does the rest. Fixes have been tested w/ the BUGS.edb in the distribution. Id: 13 Summary: Single-field records trigger warning on read Status: resolved Reported-Version: 1.28 Reported-By: ttn Reported-Date: 2007-12-11 Fix-Applied-Summary: Special-case apparent-records computation for 1-field tuples Fix-Applied-Date: 2007-12-12 Fix-Applied-Version: 1.28p1 Resolved-Date: 2008-01-16 2007-12-11 sez: In developing examples/www-links{,edb}, `edb-interact' would trigger some warning messages and eventually query: "Bad file format; try reading anyway?". Answering "yes" would successfully read in the data (anyway). 2007-12-12 sez: Looks like `db-confirm-seps' computes `apparent-records' by dividing the number of visible record separators by the number of visible field separators, when both are the same. The boundary condition where there is only one field thus results in apparent-records being 1. Fix is to special-case that computation to take `apparent-records' to be directly the count of rsep matches. Id: 14 Summary: There is no command to add a record after the current one Status: fix-applied Reported-Version: 1.22 Reported-By: bob@newell.net Reported-Date: 2003-12-10 Fix-Applied-Summary: Make db-add-record accept prefix arg and append if non-nil Fix-Applied-Date: 2008-01-16 Fix-Applied-Version: 1.29 Resolved-Date: 2008-05-24 sez (in elip.el func elip-import): ;; it probably makes the most sense to insert at the very end of ;; the file this is not easy at all since all inserts are ;; insert-before! so what we do is put in all the new records, ;; save position, go to end delete the last record, go back, and ;; yank it in front of all the new records. ugga-bugga. 2008-01-16 sez: that's ugly! looks like `database-add-record' supports append (using optional arg ENDP). we just need to bubble that up to the user-command. we can either extend `db-add-record' or add a new one. let's try the extension first and see how that goes... 2008-05-24 sez: extending `db-add-record' has been tested w/ ELIP. seems to work fine. marking this "resolved". Id: 15 Summary: Compilation fails under Windoze Status: fix-applied Reported-Version: 1.29 Reported-By: phillip.lord@newcastle.ac.uk Reported-Date: 2008-03-25 Fix-Applied-Summary: Use `call-process-region' instead of pipes Fix-Applied-Date: 2008-04-28 Fix-Applied-Version: 1.30 2008-03-25 sez (EDB is the "database dependency"): > [...] the emacs database dependency doesn't compile properly on > windows (using cygwin make). It works fine on linux. For EDB 1.29, build process uses GNU make to mine runtime values out of GNUmakefile (see lisp/bfuncs `edb-bfunc-get-GNUmakefile'), using a shell command that includes a pipe: echo ... | make -f - For EDB 1.30, we use `call-process-region' instead, which is better supported under Windoze. Id: 16 Summary: Sometimes deleting a record gives `args-out-of-range' error Status: fix-applied Reported-Version: 1.29 Reported-By: phillip.lord@newcastle.ac.uk Reported-Date: 2008-03-31 Fix-Applied-Summary: Fix OBOE in `db-delete-record' Fix-Applied-Date: 2008-05-25 Fix-Applied-Version: 1.30 2008-03-31 describes error. 2008-04-03 sends file that manifests the error (in ELIP). Analysis: For EDB 1.26 (2005-12-31), the internals were revamped to use a "vov" (vector of vectors) instead of a doubly-linked circular list. Thus deletion implementation changed from "remove element, join neighbor links" to "shift higher-indexed elements down". The "shift" is an iterative assignment to a vector index N the element found at index N+1, starting from the index of the removed element. The bug is in the computation of the shift's end index: for vector of length L, it was erronously computed to be (- L 1), whereas the correct value is (- L 2). Three more implementation details should be noted to understand how this bug has gone unnoticed for so long. - EDB keeps track of "number of records", NR, i.e., the count of how many elements (starting from index 0) in the vov are valid. Deletion does not change vov length; it simply decrements number of records. - Initial allocation of the vov is 10 plus the number of original records (see lisp/db-file-io.el `edb--snap!'). The intent of the extra space is so that immediate small additions do not incur a realloc. (Likewise, on realloc, another extra 10 slots are added.) - On deletion end-index computation actually uses NR for "L". So, for 91% of the deletions on average (10 times out of 11), the incorrect end-index does not result in any out-of-range access. Another (latent) bug is visible upon inspection: The vov's highest index, where the "hole" is moved to after the shift, is not being cleared, so continued reference to that slot's record may cause problems later. Resolution: - Bugfix: Compute end-index correctly. - Ancillary bugfix: Reset highest index (hole). - New test: b00.test BUGS database ends here. edb-1.31/BUGS.edb0000444000175000017500000001053511016251134011574 0ustar ttnttn;;; BUGS.edb -*- emacs-lisp -*- ;; Copyright (C) 2007,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :EDB (single) :name "EDB BUGS" (edb-define-enumtype 'status '("unresolved" "fix-applied" "resolved")) :record-separator "\f\n" :cruft [[["\\([^\f]*\n\\)*\f\n" 0] ["\f\n[^\n]+\n" 0]] [nil nil]] (require 'edb-t-timedate1) (edb-define-recordfieldtype 'iso-date 'date :actual->stored 'edb-t-timedate1:format-date-iso :stored->actual 'edb-t-timedate1:parse-date-string) :tagged-setup ` (:fields ,(mapcar (lambda (args) (multiple-value-bind (desc name type) args (list (cons name type) (capitalize (symbol-name name)) desc))) '(("serial number of the bug" id integer) ("one-line description of the buggy behavior" summary one-line-string) ("one of: unresolved, fix-applied, resolved" status status) ("released version of EDB that demonstrates this bug" reported-version string) ("either \"ttn\" or someone's email address" reported-by string) ("when reported (and hopefully entered into BUGS :-)" reported-date iso-date) ("one-line description of the fix" fix-applied-summary one-line-string) ("when status changed to fix-applied" fix-applied-date iso-date) ("version at and after which no longer demonstrate the bug" fix-applied-version string) ("when status changed to resolved" resolved-date iso-date) ("notes" notes string))) ;; overriding attributes :pre-tag-regexp "" :separator-regexp ":[ \t]*" :separator-output ": " :continuation-regexp "\a" :continuation-output "" :pre-parse-thunk (lambda () (let ((p (point-min)) q) (search-forward "\n\n") (delete-char -1) (insert "Notes:") (while (< (point) (point-max)) (forward-line 1) (unless (eobp) (insert "\a"))) (goto-char p))) :post-write-function (lambda (record) (while (= ?\n (char-before)) (delete-char -1)) (insert "\n\n") (save-excursion (goto-char (point-min)) (when (search-forward "Notes: " nil t) (replace-match "\n"))))) :record-defaults (lambda () (flet ((read/def (prompt def) (read-from-minibuffer prompt def nil nil nil def))) (let ((date (edb-t-timedate1:parse-date-string (read/def "When: " (current-time-string)))) (user (read/def "Reported by: " (format "%s@%s" (user-login-name) (system-name)))) (v (read/def "EDB version: " edb-version))) (list 'id (1+ (database-no-of-records dbc-database)) 'reported-version v 'reported-date date 'reported-by user 'status "unresolved" 'notes (format "%s <%s> sez:\n" (format-time-string "%F %T") user))))) :summary-format (concat "\\id,width=3,right-justify" " \\status,width=12,right-justify" " \\summary") :display t Bug: \id / EDB \reported-version / \status \summary Reported \reported-date,date-iso by <\reported-by\ > Fix applied \fix-applied-date,date-iso EDB \fix-applied-version \fix-applied-summary Resolved \resolved-date,date-iso \notes :EOTB ;;; BUGS.edb ends here edb-1.31/ChangeLog0000444000175000017500000100301011016452223012123 0ustar ttnttn2008-05-26 Thien-Thi Nguyen Release: 1.31 * configure.ac (AC_INIT): Bump version to "1.31" for release. 2008-05-26 Thien-Thi Nguyen Specify metadata for $(infodir)/dir. * doc/edb.texi: Add @dircategory and @direntry. 2008-05-26 Thien-Thi Nguyen Fix bug introduced in EDB 1.30 (2008-01-22): DTRT for "make install" in subdir doc/. * doc/GNUmakefile.in (ii): New var. (install): Fix bug: Don't use defunct var; hardcode "edb.info". Also, add code to test install-info(1) and use it if suitable. 2008-05-26 Thien-Thi Nguyen Release: 1.30 * configure.ac (AC_INIT): Bump version to "1.30" for release. 2008-05-25 Thien-Thi Nguyen In Database Edit mode, make `C-k' respect `kill-whole-line'. * lisp/db-format.el (db-kill-line): Respect `kill-whole-line'. 2008-05-25 Thien-Thi Nguyen When deleting a record, clear highest (post-shift) vov element. * lisp/db-interfa.el (db-delete-record): Clear highest after shift. 2008-05-25 Thien-Thi Nguyen Use local variable to reduce number of calls to `edb--S'. * lisp/db-format.el (db-next-field-internal) (db-previous-field-internal, dbf-process-field-maybe) (db-change-format, dbf-set-summary-format, db-display-record) * lisp/db-interfa.el (dbc-set-index, db-select-next-record) (db-delete-record, db-mark-record, db-hide-record) * lisp/db-summary.el (db-summary): Use local variables. 2008-05-25 Thien-Thi Nguyen In Database Edit mode, `C-a' / `C-e' twice moves to field limit. * lisp/db-format.el (db-beginning-of-line-or-field): If invoked twice in succession, move to beginning of field. (db-end-of-line-or-field): Likewise, for end of field. 2008-05-24 Thien-Thi Nguyen On save, if file -w, query user for "chmod +w and continue". * lisp/db-file-io.el (db-write-1): If the file is not writable, and this is an interactive session, offer to make it writable and continue, else error out. 2008-05-24 Thien-Thi Nguyen Use GNUmakefile throughout. * skram/GNUmakefile-atvars.in: Delete file. * skram/GNUmakefile.in: Rename from GNUmakefile; incorporate GNUmakefile-atvars.in. * configure.ac (AC_CONFIG_FILES): Delete tests/Makefile and skram/GNUmakefile-atvars; add tests/GNUmakefile and skram/GNUmakefile. 2008-05-24 Thien-Thi Nguyen Fix OBOE introduced w/ EDB 1.26 (2005-10-08): When deleting a record, limit shift-in count properly. * lisp/db-interfa.el (db-delete-record): Fix OBOE: For shift-in, stop at one-before-end instead of end. 2008-04-28 Thien-Thi Nguyen Revamp "make dist". * GNUmakefile.in (skramdist, bugfiles, docfiles): Delete var. (extradist): New vars. (distfiles): Delete var. (minusdist): New var. (dist): CHeck for .git subdir; use "git ls-files"; modify installed database.el in place; specify maximum compression for gzip. 2008-04-28 Thien-Thi Nguyen Make "make installcheck" recursive. * lisp/GNUmakefile.in (installcheck): New target. * doc/GNUmakefile.in (installcheck): Likewise. * GNUmakefile.in (installcheck): Remove rules; depend on `installcheck-recursive'. 2008-04-28 Thien-Thi Nguyen Fix omission bug: Don't let make say "Entering/Leaving directory". * lisp/bfuncs (edb-bfunc-get-GNUmakefile): Specify `--no-print-directory'. Reported by Phillip Lord. 2008-03-31 Thien-Thi Nguyen Make build process more portable. * lisp/bfuncs (edb-bfunc-get-GNUmakefile): Fix portability bug: Avoid pipes; use `with-temp-buffer' and `call-process-region' instead. Reported by Phillip Lord. 2008-01-24 Thien-Thi Nguyen * doc/GNUmakefile.in (prep-dist): Remove more temporary files. 2008-01-24 Thien-Thi Nguyen * doc/edb.texi: Use @copying and @insertcopying. 2008-01-23 Thien-Thi Nguyen * doc/GNUmakefile.in (%.ps:%.dvi): Delete .aux and .log when done. 2008-01-22 Thien-Thi Nguyen * doc/edb.texi: Rename from edb.texi. * doc/GNUmakefile.in (all): Depend on edb.info. (edb.info, version.texi): New targets. (.tex.dvi, .texi.dvi): New pattern rules. (clean): Also delete edb.info. (prefix, dataroot, datadir, infodir) (INSTALL, INSTALL_DATA, mkinstalldirs): New vars. (install): New target. * GNUmakefile.in (INFO-FILES): Update location of edb.info. (all): Recurse into subdir `doc'. (edb.info, version.texi): Delete targets. (.tex.dvi, .texi.dvi): Delete pattern rules. (maintainerclean): No longer delete edb.info. (docfiles): Update location of edb.texi and version.texi. * skram/make-skram.el (make-skram): Update edb.info location. * skram/GNUmakefile (elisp): Update location of .el files. * lisp/bfuncs: Rename from bfuncs. * lisp/database.el: Rename from database.el. * lisp/db-file-io.el: Rename from db-file-io.el. * lisp/db-format.el: Rename from db-format.el. * lisp/db-interfa.el: Rename from db-interfa.el. * lisp/db-isbn.el: Rename from db-isbn.el. * lisp/db-lemacs.el: Rename from db-lemacs.el. * lisp/db-nosetf.el: Rename from db-nosetf.el. * lisp/db-oldnames.el: Rename from db-oldnames.el. * lisp/db-rdb.el: Rename from db-rdb.el. * lisp/db-rep.el: Rename from db-rep.el. * lisp/db-search.el: Rename from db-search.el. * lisp/db-sort.el: Rename from db-sort.el. * lisp/db-summary.el: Rename from db-summary.el. * lisp/db-tagged.el: Rename from db-tagged.el. * lisp/db-two-dbs.el: Rename from db-two-dbs.el. * lisp/db-types.el: Rename from db-types.el. * lisp/db-util.el: Rename from db-util.el. * lisp/edb-t-human-names.el: Rename from edb-t-human-names.el. * lisp/edb-t-places-usuk.el: Rename from edb-t-places-usuk.el. * lisp/edb-t-timedate1.el: Rename from edb-t-timedate1.el. * lisp/GNUmakefile.in: New file. * GNUmakefile.in (EMACS, EXTRABATCHOPTS, edb-elc-dir, TEXI2DVI, ebatch) (VPATH, edbcore-lispfrags, edbcore-dbfrags, edbcore-components) (generated, dontcompile, typelib-frags, typelibs) (normal-lispfrags, normal-frags, normal) (source-el-files, installed-el-files, installed-elc-files) (badnamesp, badnames-el): Delete vars. ($(installed-elc-files)): Delete target. (recursive-%): New pattern rule. (all, install, clean): Rewrite targets. * configure.ac (AC_CONFIG_FILES): Add lisp/GNUmakefile. 2008-01-22 Thien-Thi Nguyen * GNUmakefile.in (dist): No longer worry about "CVS" subdirs. 2008-01-22 Thien-Thi Nguyen * skram/retired.data: New file. 2008-01-17 Thien-Thi Nguyen * configure.ac (AC_INIT): Bump version to "1.29" for release. 2008-01-17 Thien-Thi Nguyen * GNUmakefile.in (rw-ok): Add examples/www-links, examples/www-links2 and examples/www-links3. (dist): For $(distfiles), dereference symlinks on cp(1). 2008-01-17 Thien-Thi Nguyen * edb.texi (Top, Specifying control): Add "Example control file from scratch" to menus. (Example control file from scratch): New node/section. 2008-01-16 Thien-Thi Nguyen * BUGS.edb (:tagged-setup :post-write-function): Handle missing "Notes: ". (:record-defaults): Update `id' value. 2008-01-16 Thien-Thi Nguyen * BUGS.edb (:record-defaults): Rewrite. 2008-01-16 Thien-Thi Nguyen * db-interfa.el (db-yank-record): Minor reimpl; nfc. 2008-01-15 Thien-Thi Nguyen * db-interfa.el (db-add-record): Take optional arg APPEND. If non-nil, add after last record. Update informative message to say "Appended" or "Inserted". * edb.texi (Adding and removing records): Update `db-add-record'. 2008-01-15 Thien-Thi Nguyen * BUGS.edb (:record-defaults): Fix typo. 2008-01-15 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Handle schema basis. * edb.texi (Specifying control): Document schema basis. 2008-01-15 Thien-Thi Nguyen * db-util.el (db-string-trim-whitespace): Rewrite. 2008-01-14 Thien-Thi Nguyen * db-file-io.el (db-write-1): Fix bug introduced 2006-06-29: Call inherent's :seqw w/ three args, not four. 2007-12-31 Thien-Thi Nguyen * lisp/edb-1int-to-single.el (edb-1int-to-single): Fix bug: Format :locals as in a let-bindings block. 2007-12-29 Thien-Thi Nguyen * db-interfa.el (dbf-finished-sorting): Fix omission bug: If :record/before-sorting or :buffer/before-sorting are unspecified, default to first record and current buffer, respectively. 2007-12-29 Thien-Thi Nguyen * db-interfa.el (dbf-finished-sorting): Use `prog1'. 2007-12-27 Thien-Thi Nguyen * edb.texi (Kinds of control property values): Define macro `cpropvaltype'; use it; undefine it. 2007-12-27 Thien-Thi Nguyen * edb.texi (Display specification optional parameters): Define macros `dslot' and `dslotx'; use them; undefine them. 2007-12-27 Thien-Thi Nguyen * edb.texi (Predefined displaytypes): Define macros `dtype' and `dtypex'; use them; undefine them. 2007-12-27 Thien-Thi Nguyen * edb.texi (Record field attributes): Define macro `rfattr'; use it; undefine it. (Predefined record field types): Define macro `rftype'; use it; undefine it. 2007-12-27 Thien-Thi Nguyen * db-file-io.el (db-read-database-file-helper): Fix omission bug: For `rsep', when pre-first or post-last regexp matches, save the text in the respective -string slot for later output. * BUGS.edb (:cruft): Specify regexp for eof blurb. (iso-date): New recordfieldtype. (:fields): Use `iso-date'. Also, add :post-write-function. 2007-12-26 Thien-Thi Nguyen * edb.texi (Tagged file layout): Define macro `tskeyword'; use it; undefine it. 2007-12-26 Thien-Thi Nguyen * edb.texi (Control properties reference): Define macro `cprop'; use it; undefine it. 2007-12-26 Thien-Thi Nguyen * database.el: Add autoload form for `edb-1int-to-single'. * edb.texi (edb-1int-to-single): No longer mention `require' form. 2007-12-21 Thien-Thi Nguyen * db-util.el (edb-hookp): New func. * db-file-io.el (db-before-read-hooks, db-after-read-hooks): Use `edb-hookp' for property `safe-local-variable'. 2007-12-21 Thien-Thi Nguyen * db-file-io.el (db-before-read-hooks, db-after-read-hooks): Specify property `safe-local-variable'. 2007-12-13 Thien-Thi Nguyen * database.el (edb-version): Use "%s" as first arg to `message'. * db-format.el (db-edit-mode): Likewise. 2007-12-12 Thien-Thi Nguyen * autogen.sh: If COPYING is GPLv2, try to find and symlink GPLv3. If not successful, output a warning. 2007-12-12 Thien-Thi Nguyen * database.el (edb-EXPERIMENTAL-interact): Delete alias. 2007-12-12 Thien-Thi Nguyen * db-file-io.el (db-confirm-seps): Fix bug: When there is only one field, take apparent-records to be directly the count of rsep matches. 2007-12-11 Thien-Thi Nguyen * db-file-io.el (db-read-file-delimited, db-read-file-delimstr) (db-read-file-delimrx, db-write-intdelim): Use `pp-to-string'. 2007-08-28 Thien-Thi Nguyen * ANONCVS: Delete file. 2007-05-29 Thien-Thi Nguyen * configure.ac (AC_INIT): Bump version to "1.28" for release. 2007-05-28 Thien-Thi Nguyen * db-rep.el (db-lmap): Check :locals `db-inform-interval' in preference to Emacs Lisp var by same name. * edb.texi (Ongoing migration): Remove `db-inform-interval'. (Global variables): Add blurb and @ref. 2007-05-28 Thien-Thi Nguyen * db-sort.el (database-sort): Check :locals `db-sort-modifies-p' in preference to Emacs Lisp var by same name. * edb.texi (Sort interface): Mention `:locals' for `db-sort-modifies-p'. (Ongoing migration): Remove `db-sort-modifies-p'. 2007-05-28 Thien-Thi Nguyen * edb.texi (Control properties reference): For :locals, say "mostly opaque". 2007-05-28 Thien-Thi Nguyen * lisp/connection.el (edb--1run-hook-with-arg): New func. * db-format.el (dbf-set-this-record-modified-p): Use `edb--1run-hooks'. (dbf-process-current-record-maybe): Use `edb--1run-hook-with-arg'. * edb.texi (Ongoing migration): Remove `dbf-set-this-record-modified-function' and `dbf-after-record-change-function'. (Display format change hooks): Add blurb and @ref. 2007-05-28 Thien-Thi Nguyen * lisp/connection.el (edb--1run-hooks): New func. * db-format.el (db-view-mode, db-edit-mode) (db-move-to-field-exact, db-next-field, db-previous-field) (db-first-field, db-jump-to-point): Use `edb--1run-hooks'. * db-summary.el (database-summary-mode): Use `edb--1run-hooks'. * edb.texi (Ongoing migration): Remove `dbf-enter-field-hook'. (Edit mode hooks): Add @ref to "Database mode hooks". 2007-05-28 Thien-Thi Nguyen * db-format.el (db-view-mode, db-edit-mode): Also check locals for `db-view-mode-hooks' and `db-edit-mode-hooks', respectively. * db-summary.el (database-summary-mode): Also check locals for `database-summary-mode-hooks'. * edb.texi (Ongoing migration): Remove `db-view-mode-hooks', `db-edit-mode-hooks' and `database-summary-mode-hooks'. (Database mode hooks): Document `:locals' control property technique. 2007-05-28 Thien-Thi Nguyen * lisp/connection.el (edb--1mm<-connection): Fix bug: Don't eval init form of each `:locals' binding pair. 2007-05-28 Thien-Thi Nguyen * BUGS.edb: New file. * GNUmakefile.in (bugfiles): New var. (distfiles): Use $(bugfiles). 2007-05-28 Thien-Thi Nguyen * doc/GNUmakefile.in (prep-dist): New target. (clean): Depend on prep-dist. 2007-05-28 Thien-Thi Nguyen * doc/refcard.texi: Set top margin. Decrease column separation slightly. Use small-caps for title. Do vskip before the end copyright notice. (prop, dsopt): New commands. (control file properties): New section. (displayspec options): New section. (builtin types): New section. 2007-05-26 Thien-Thi Nguyen * edb.texi (Control properties reference): Fix typo. 2007-05-26 Thien-Thi Nguyen * doc/refcard.tex: Convert to LaTeX. * doc/GNUmakefile.in (TEX): Delete var. (LATEX): New var. (%.dvi:%.tex): Use $(LATEX). 2007-05-26 Thien-Thi Nguyen * doc/refcard.tex (in view mode): Mention `y', `t' and `+'. 2007-05-26 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Skip comments and blank lines before looking for identifying cookie. * edb.texi (Specifying control): Mention that ":EDB" is looked for on the first non-comment, non-blank line. 2007-05-26 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Use `insert-buffer-substring'. 2007-05-24 Thien-Thi Nguyen * doc/refcard.tex (columnsperpage): Set to 3. * doc/GNUmakefile.in (DVIPDF): Delete var. (PS2PDF): New var. (%.ps:%.dvi): Use `-t landscape'. (%.pdf:%.dvi): Delete pattern rule. (%.pdf:%.ps): New pattern rule. 2007-05-24 Thien-Thi Nguyen * doc/refcard.tex (letterpaper): New \newcount; init to 0 (A4). Throughout, conditionalize on \letterpaper value. Also, define \font\eightmi and set \textfont1. 2007-05-24 Thien-Thi Nguyen * doc/refcard.tex: Add \par at end of \tiny block. 2007-05-24 Thien-Thi Nguyen * doc/refcard.tex: Use `\"a' instead of `ae'. 2007-05-02 Erich Waelde * doc/refcard.tex (tinyfont, tinysy): New \font names. (tiny): New \def. (copyrightnotice): Use \tiny. 2007-05-01 Thien-Thi Nguyen * doc/refcard.tex (year, versionnumber, updated): Delete. Input refcard.version.tex, instead. * doc/GNUmakefile.in (VERSION): New var. (all): New target. (%.dvi): Depend also on refcard.version.tex. (refcard.version.tex): New target. 2007-05-01 Thien-Thi Nguyen * GNUmakefile.in (docfiles): New var. (distfiles): Use $(docfiles). (dist): Also create subdir $(dd)/doc. 2007-05-01 Thien-Thi Nguyen * GNUmakefile.in (all): No longer do symlinking. * configure.ac (symlinks): New AC_CONFIG_COMMANDS block. 2007-05-01 Thien-Thi Nguyen * doc/refcard.tex (author, year): New defs. (shortcopyrightnotice): Remove spacing. (copyrightnotice): Use \shortcopyrightnotice; add text. [document]: Use \shortcopyrightnotice after title; use \copyrightnotice right before \bye. 2007-05-01 Thien-Thi Nguyen * doc/refcard.tex: New file. * doc/GNUmakefile.in: New file. * configure.ac (AC_CONFIG_FILES): Add doc/GNUmakefile. 2007-04-30 Thien-Thi Nguyen * db-format.el (db-ds+opts-rx): Rewrite w/ two subexps. (db-dspec<-string): Update `db-ds+opts-rx' handling. (db-string->displaytype): Delete func. (db-dspec<-dtype, db-dspec<-type/opts): Use `intern' directly. 2007-04-30 Thien-Thi Nguyen * db-format.el (db-symbol-regexp, db-dtrx, db-fopt, db-dsym): Delete. (db-ds+opts-rx): New const string. (db-pad-left): New func. (db-optspec-list): Use `db-pad-left'. (db-dspec<-string): Handle options as list of strings. (db-dspec<-type/opts): Likewise. (db-setup-ddb-parse-displayspecs): Use `db-ds+opts-rx'. Update match beginning/end extraction computation. * db-summary.el (db-format->lines/sforms): Use `db-ds+opts-rx'. Update match beginning/end extraction computation. * db-types.el (edb-define-enumtype): Update `db-dspec<-type/opts' call. 2007-04-27 Thien-Thi Nguyen * db-interfa.el (db-sort): Note current "before-sorting" buffer. (dbf-finished-sorting): When done, switch to noted buffer. 2007-04-26 Thien-Thi Nguyen * db-summary.el (database-summary-mode-map): Bind `S' to `db-sort'. 2007-04-24 Thien-Thi Nguyen * db-file-io.el (database-perform-substitutions): In error message, use one space after the colon. * db-types.el (db-string-match-actual->display): Likewise. * db-util.el (db-string->integer): Likewise. 2007-04-24 Thien-Thi Nguyen * GNUmakefile.in (all): Symlink /dev/null. (dist): Also remove $(dd)/examples/null. 2007-04-24 Thien-Thi Nguyen * db-file-io.el (db-confirm-seps): Avoid divide-by-zero. 2007-04-24 Thien-Thi Nguyen * db-format.el (db-setup-ddb-parse-displayspecs): If no :sumfmt can be determined, synthesize one. 2007-04-23 Thien-Thi Nguyen * db-summary.el (dbf-fill-summary-buffer): Take optional arg MOVEP. If non-nil, call `dbs-move-to-proper-record' after filling. (dbf-fill-summary-buffer-and-move-to-proper-record): Delete func. * db-interfa.el (db-hiding-toggle, db-toggle-show-hidden-records): Call `dbf-fill-summary-buffer' with non-nil MOVEP. 2007-04-23 Thien-Thi Nguyen * db-file-io.el (db-reading-noninternal): Fix `(decare (debug ...))' spec. 2007-04-23 Thien-Thi Nguyen * db-sort.el (database-ordered-p): If any contiguous elements are unordered return nil immediately. 2007-04-23 Thien-Thi Nguyen * configure.ac (AC_INIT): Add third arg. 2007-04-22 Thien-Thi Nguyen * GNUmakefile.in (datarootdir): New var. 2007-04-22 Thien-Thi Nguyen * autogen.sh (amfiles): Remove mkinstalldirs. * GNUmakefile.in (mkinstalldirs): Use `install-sh -d'. (distfiles): Remove mkinstalldirs. 2006-07-31 Thien-Thi Nguyen * database.el (edb-interact): Rename from `edb-EXPERIMENTAL-interact'. (edb-EXPERIMENTAL-interact): New alias. * edb.texi: Throughout, use `edb-interact'. 2006-07-31 Thien-Thi Nguyen * db-format.el (database-view-mode, database-edit-mode): New aliases. 2006-07-31 Thien-Thi Nguyen * skram/skram.fmt, skram/skram.edb: In summary format, reduce width for `kind' to 10. 2006-07-30 Thien-Thi Nguyen * db-rep.el (edb--field-nm2no): Delete func. * db-format.el (dbf-set-change-function, db-dspec<-string) * db-sort.el (db-convert-ordering-fields) (db-make-ordering-fields-canonical) * db-tagged.el (db-tagged-setup) * db-rdb.el (db-rdb-list-wrfr): Use :nm2no directly. 2006-07-30 Thien-Thi Nguyen * db-rep.el (database-empty-p): Delete defsubst. * db-sort.el (database-sort): Incorporate `database-empty-p'. * db-summary.el (db-summary): Likewise. * db-two-dbs.el (db-process-two-databases): Don't use `database-empty-p'. 2006-07-29 Thien-Thi Nguyen * edb.texi (Specifying a record field type): Remove doc for `define-recordfieldtype-from-recordfieldspec'. (Enumeration displaytypes): Remove doc for `define-enum-type'. (Defining new displaytypes): Remove doc for `define-displaytype-from-displayspec'. 2006-07-27 Thien-Thi Nguyen * db-tagged.el (db-tagged-write): No longer recognize `db-tagged-wrfr-before-hooks' and `db-tagged-wrfr-after-hooks'. (db-tagged-read): No longer recognize `db-tagged-rrfr-hooks'. * edb.texi (Tagged file layout): Remove docs and intro blurb for `db-tagged-rrfr-hooks', `db-tagged-wrfr-before-hooks' and `db-tagged-wrfr-after-hooks'. 2006-07-27 Thien-Thi Nguyen * db-interfa.el (db-field-query-replace) * db-two-dbs.el (database-compare-hack): Use :elaborated-rfspecs from global hash. 2006-07-27 Thien-Thi Nguyen * db-rep.el (db-rs-slice): New func. (database-set-fieldnames-to-list): Set :rs-slices and :elaborated-rfspecs in the global hash. (database-recordfieldspec): Delete func. (db-check-constraint): Use `db-rs-slice'. * db-file-io.el (db-read-file-delimstr) (database-stored->actual, db-write-intdelim): Use `db-rs-slice'. * db-format.el (db-dspec<-string): Use `db-rs-slice'. * db-interfa.el (db-field-help, db-add-record) (db-field-query-replace): Use `db-rs-slice'. (db-search-field): Use :elaborated-rfspecs from global hash. * db-sort.el (db-convert-ordering-fields): Use :elaborated-rfspecs from global hash. * db-tagged.el (db-tagged-setup): Use `db-rs-slice'. * db-two-dbs.el (db-merge-records, databases-compatible) (database-compare-hack): Use `db-rs-slice'. * db-rdb.el (db-rdb-list-wrfr): Use `db-rs-slice'. * edb.texi (Specifying a record field type): Remove doc and associated blurb for `database-recordfieldspec'. 2006-07-27 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Deconstruct names and types; call `database-set-fieldnames-to-list' to do reconstruction and elaboration. 2006-07-27 Thien-Thi Nguyen * lisp/edb-meta.el (edb-meta): Set `revert-buffer-function'. 2006-07-25 Thien-Thi Nguyen * skram/retired.edb, skram/skram.edb: Make sure all text blocks end with :EOTB. 2006-07-25 Thien-Thi Nguyen * db-rep.el (database-set-recordfieldspec): Delete func. * db-rdb.el (db-rdb-setup): Incorporate deleted func. * db-tagged.el (db-tagged-setup): Likewise. * edb.texi (Specifying a record field type): Remove its doc, too. 2006-07-25 Thien-Thi Nguyen * db-rep.el (database-recordfieldspec-type): Delete func. * db-format.el (db-dspec<-string): Incorporate deleted func. * edb.texi (Specifying a record field type): Remove its doc, too. 2006-07-25 Thien-Thi Nguyen * edb-t-timedate1.el (edb-t-timedate1:format-date-mmddy) (edb-t-timedate1:format-date-ddmmyy) (edb-t-timedate1:format-date-yymmdd) (edb-t-timedate1:format-date-ddmmmyy) (edb-t-timedate1:format-date-yyyymmdd): Remove support for "FOO-separator" variables. 2006-07-13 Thien-Thi Nguyen * configure.ac (AC_INIT): Bump version to "1.27" for release. 2006-07-13 Thien-Thi Nguyen * GNUmakefile.in (rw-ok): Add examples/geneal.dat. 2006-07-12 Thien-Thi Nguyen * lisp/edb-meta.el (edb-meta): Also display symbols w/ non-nil default bindings, prefixed with "(v)" and/or "(f)". (globals-to-check): Specify this property for symbol `edb-meta'. 2006-07-12 Thien-Thi Nguyen * db-rep.el (edb--T, edb--T!): Delete defsubsts. 2006-07-12 Thien-Thi Nguyen * db-rdb.el (db-tagged-setup): Use :rdb-details instead of `edb--T' and `edb--T!'. Also, use `edb--mputhash'. (db-rdb-database-stored->actual, db-rdb-list-rrfr) (db-rdb-list-wrfr, db-rdb-read-fields): Use :rdb-details. 2006-07-12 Thien-Thi Nguyen * db-tagged.el (db-tagged-spec-name, db-tagged-spec-tag) (db-tagged-spec-help): Incorporate into unique caller. 2006-07-12 Thien-Thi Nguyen * db-tagged.el (db-tagged-setup): Use :tagged-details instead of `edb--T' and `edb--T!'. Also, move attribute syntax check earlier in function. Also, use `edb--mputhash', `db-tagged-read' and `db-tagged-write', and set up :tagged-read-kargs and likewise :tagged-write-kargs for the latter two. (db-tagged-convert/index): Use :tagged-details. (db-tagged-rrfr, db-tagged-wrfr): Delete funcs. (db-tagged-read, db-tagged-write): New funcs. 2006-07-11 Thien-Thi Nguyen * db-tagged.el (db-tagged-setup): Don't copy and modify recordfieldspecs. Instead, use `db-set-field-help' and elaborate recordfieldspecs afterwards. * db-rdb.el (db-rdb-setup): Likewise. 2006-07-11 Thien-Thi Nguyen * db-interfa.el (db-set-field-help): New func. (db-field-help): Consult :field-help as well. Display both help sources separated by two newlines. * edb.texi (Specifying a record field type): Document `db-set-field-help'. 2006-07-09 Thien-Thi Nguyen * db-tagged.el (db-tagged-wrfr): Use `dolist'. 2006-07-08 Thien-Thi Nguyen * db-tagged.el (db-tagged-setup): Doc fix. 2006-07-08 Thien-Thi Nguyen * db-format.el (db-setup-data-display-buffer): Use `insert-buffer-substring'; remove properties "manually" later after local variables processing. * lisp/system.el (insert-buffer-substring-no-properties): Delete func. * lisp/connection.el (edb--1mm<-connection): For :locals, accept let-bindings-block style two-element list, instead of simple pair. (edb--1format-buffer<-connection): Store eval forms in a text property. Also, handle locals with a `database-make-local' form. * edb.texi (Control properties reference): Update :locals docs. 2006-07-08 Thien-Thi Nguyen * db-tagged.el (db-tagged-convert/index): New func. (db-tagged-before-read): Delete func. (db-tagged-database-stored->actual): Delete func. (db-tagged-setup): Incorporate `db-tagged-before-read'. Handle attribute :index-function. Use `db-tagged-convert/index'. * edb.texi (Tagged file layout): Document :index-function. Also, mention restriction on use of `db-after-read-hooks'. 2006-07-07 Thien-Thi Nguyen * db-format.el (db-setup-data-display-buffer): No longer check for and call `crypt-insert-file-contents'. 2006-07-06 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Fix omission bug: While looping, skip comments before doing the bounds check. 2006-07-03 Thien-Thi Nguyen * db-format.el (db-view-mode, db-edit-mode): Include "Database " in mode name. (database-mode): Remove "Database:" from mode line. * db-summary.el (database-summary-mode): For mode line, remove "Database:" and use `mode-name'. * db-sort.el (database-sort-interface-mode): Remove "Database Sort:" from mode line. * edb.texi (Database mode): Update example mode line and associated explanation. 2006-07-03 Thien-Thi Nguyen * edb-t-timedate1.el (edb-t-timedate1:format-date-iso): New func. (date-iso): New displaytype. * edb.texi (Predefined displaytypes): Mention `date-iso'. 2006-07-03 Thien-Thi Nguyen * edb-t-timedate1.el (edb-t-timedate1:format-date-mmddyy-separator): Delete defconst. (edb-t-timedate1:format-date-ddmmyy-separator): Delete defvar. (edb-t-timedate1:format-date-yymmdd-separator): Delete defconst. (edb-t-timedate1:format-date-ddmmmyy-separator): Delete defvar. (edb-t-timedate1:format-date-yyyymmdd-separator): Delete defconst. (edb-t-timedate1:format-date-mmddyy) (edb-t-timedate1:format-date-ddmmyy) (edb-t-timedate1:format-date-yymmdd) (edb-t-timedate1:format-date-ddmmmyy) (edb-t-timedate1:format-date-yyyymmdd): Take optional arg SEPARATOR. If specified, use it as separator. Otherwise, look for similarly-named symbol variable binding and use that. Otherwise, use a default. (edb-t-timedate1:format-date-dec, edb-t-timedate1:format-date-europe): Update calling sequence to lower-level function to pass separator. * edb.texi (Predefined displaytypes): Split `date'-based displaytypes into two groups. Mention that first group takes optional arg. 2006-07-02 Thien-Thi Nguyen * edb-t-timedate1.el (edb-t-timedate1:format-date-ddmmyy): Fix bug: Use "%dd" and "%mm". (edb-t-timedate1:format-date-ddmmmyy): Fix bug: Use "%dd". (edb-t-timedate1:format-date-yyyymmdd): Fix bug: Use "%mm" and "%dd". Reported by Erich Waelde. 2006-07-02 Thien-Thi Nguyen * edb-t-timedate1.el (edb-t-timedate1:format-date-sub-syms-alist): Wrap each expression in an anonymous 1-ary function. (edb-t-timedate1:format-date): Use `funcall'. 2006-07-01 Thien-Thi Nguyen * edb-t-timedate1.el (edb-t-timedate1:format-date-sub-syms-alist): Make table concise; build data structure at compile time. 2006-07-01 Thien-Thi Nguyen * edb-t-timedate1.el (edb-t-timedate1:format-date-sub-syms-alist): Fix bug: Ensure that `yy' rendering produces two characters. 2006-06-29 Thien-Thi Nguyen * database.el (edb-EXPERIMENTAL-interact): Fix omission bug: If control has no associated filename, use the buffer name. Also, for inherent data, create a child hash under :edb1 :1singles DATABASE, and initialize it w/ various properties from the control tree. * db-file-io.el (db-write-1): Handle inherent data. * edb.texi (Control properties reference): Rewrite entry for :data. 2006-06-29 Thien-Thi Nguyen * lisp/connection.el (write-line): New :edb1 :seq-funcs init. 2006-06-28 Thien-Thi Nguyen * database.el (edb-EXPERIMENTAL-interact): For inherent data, drop records from connection tree. 2006-06-28 Thien-Thi Nguyen * db-interfa.el (db-write-database-file): Display alternative message for inherent data. 2006-06-28 Thien-Thi Nguyen * db-rep.el (1D): Use `edb--mputhash'. 2006-06-28 Thien-Thi Nguyen * GNUmakefile.in (rw-ok): New var. (dist): Make writeable files listed in $(rw-ok). 2006-06-28 Thien-Thi Nguyen * lisp/edb-meta.el (edb-meta fo): Use `safe-length' for `cons' objects. 2006-06-28 Thien-Thi Nguyen * lisp/state.el (edb--mputhash): New func. 2006-06-27 Thien-Thi Nguyen * database.el (edb-EXPERIMENTAL-interact): When CONTROL is a filename, use its nondirectory part as the buffer name. 2006-06-26 Thien-Thi Nguyen * lisp/connection.el (edb--connect): For `conn', drop plist F. 2006-06-25 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Don't delete parsed text. Also, for :data, stash :tb-start and :tb-finish as well. 2006-06-25 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Fix omission bug: Save value of call to `plist-put' back to the plist. 2006-06-23 Thien-Thi Nguyen * db-file-io.el (db-read-database-file): For inherent data, handle SOURCE in the form of (FILENAME RECORD...). Also, propertize :file value w/ the given FILENAME. * db-interfa.el (db-find-read-in-database): For the filename "(inherent)", consult its :file text property for the actual filename. * database.el (edb-EXPERIMENTAL-interact): Update calls to `db-find-read-in-database' and `db-read-database-file' to support filename saving and comparison for inherent data. 2006-06-21 Thien-Thi Nguyen * lisp/edb-meta.el (edb-meta): Also display LEN for cons. 2006-06-21 Thien-Thi Nguyen * lisp/connection.el (:edb1 :schema-schema 'single): Add :runtime-keys and some values for it. * db-util.el (edb--brpops): New var. (edb--S, edb--S!): Rewrite, and as macros. (edb--POV): Delete var. (edb-get, edb-put): Rewrite. * db-format.el (db-make-data-display-buffer): Init `edb--bprops'. * db-summary.el (db-summary): Likewise. * db-sort.el (database-sort-interface): Likewise. * edb.texi (Top): Add to detailed menu: "Changing control properties at runtime". (Specifying control): Also, add it to this menu. (Changing control properties at runtime): New node/section. 2006-06-19 Thien-Thi Nguyen * db-format.el (db-make-data-display-buffer): Use :wraparound. * db-util.el (edb-get, edb-put): Use :wraparound. * db-interfa.el (db-select-next-record): Use :wraparound. 2006-06-17 Thien-Thi Nguyen * db-util.el (edb-put): Use `pop'. 2006-06-16 Thien-Thi Nguyen * lisp/edb-meta.el: New file. * GNUmakefile.in (normal-lispfrags): Add meta. * database.el (edb-meta): Add autoload form for this command. * edb.texi (In case of trouble): Add @defun for `edb-meta'. 2006-06-15 Thien-Thi Nguyen * edb.texi (Specifying control): Add @cindex. 2006-06-11 Thien-Thi Nguyen * db-util.el (edb-true): New func. * db-format.el (dbf-set-this-record-modified-function) (dbf-before-display-record-function, dbf-enter-field-hook) (dbf-first-change-function, dbf-every-change-function) (dbf-after-record-change-function, dbf-format-name-spec-alist): Add safe-file-local-variable cookie. * db-interfa.el (db-new-record-function): Likewise. * bfuncs (edb-bfunc-make-edbcore): Handle "safe-file-local-variable cookies". 2006-06-11 Thien-Thi Nguyen * configure.ac (badnamesp): New AC_SUBST var. (badnames): New AC_ARG_ENABLE. * GNUmakefile.in (badnamesp, badnames-el): New vars. (install): Remove $(badnames-el) unless $(badnamesp). * bfuncs (edb-bfunc-make-edbcore): Remove "badnames cookies" and, if disabled, the line immediately following each of them. * db-types.el, db-rep.el: Add "badnames cookies". 2006-06-11 Thien-Thi Nguyen * db-format.el (db-callconvert): Make into a function. 2006-06-10 Thien-Thi Nguyen * db-isbn.el, db-types.el, edb-t-timedate1.el: Throughout, use `edb-define-displaytype' and `edb-define-recordfieldtype'. 2006-06-10 Thien-Thi Nguyen * db-types.el (edb-define-displaytype, edb-define-recordfieldtype) (edb-define-enumtype): Rename from `define-displaytype-from-displayspec', `define-recordfieldtype-from-recordfieldspec' and `define-enum-type', respectively. Define the old names as aliases for the new ones. * edb.texi: Throughout, rename to `edb-define-displaytype' `edb-define-recordfieldtype' and `edb-define-enumtype' from `define-displaytype-from-displayspec', `define-recordfieldtype-from-recordfieldspec' and `define-enum-type', respectively. Mention that the old names are available as aliases. 2006-06-09 Thien-Thi Nguyen * db-types.el (define-type-alias): Delete func. 2006-06-09 Thien-Thi Nguyen * db-types.el (define-one-char-enum-displaytype): Delete func. * edb.texi (One-character enumeration displaytypes): Delete node. (Multi-character enumeration displaytypes): Merge into parent node. (Top): Update detailed menu. 2006-06-09 Thien-Thi Nguyen * db-types.el (define-displaytype-from-optstring): Delete func. * edb.texi (Defining new displaytypes): Remove "two ways" intro. Say explicitly: use `define-displaytype-from-displayspec'. 2006-06-09 Thien-Thi Nguyen * db-util.el (deflocalvar): Delete macro. * db-format.el (dbf-set-this-record-modified-function) (dbf-redisplay-entire-record-p, dbf-before-display-record-function) (dbf-enter-field-hook, dbf-first-change-function) (dbf-every-change-function, dbf-after-record-change-function) (dbf-format-name-spec-alist): Make into a defvar. (db-make-data-display-buffer): Make these variables buffer-local. 2006-06-09 Thien-Thi Nguyen * db-format.el (dbf-set-this-record-modified-p): Use `when'. 2006-06-09 Thien-Thi Nguyen * db-interfa.el (db-new-record-function): Make into a defvar. * db-format.el (db-make-data-display-buffer): Make `db-new-record-function' buffer-local. 2006-06-08 Thien-Thi Nguyen * db-file-io.el (db-read-file-delimited): Fix bug: Replace match w/ literal text. * db-format.el (db-setup-ddb-parse-displayspecs): Use `delete-region'. Also, fix bug: Replace match w/ literal text. 2006-06-06 Thien-Thi Nguyen * db-summary.el (db-summary): Use `buffer-local-value'. 2006-06-06 Thien-Thi Nguyen * db-interfa.el (dbc-database): Make into a defvar. (db-find-file): Assert that `dbc-database' is buffer-local. * db-summary.el (db-summary): Make `dbc-database' buffer-local. * db-format.el (db-make-data-display-buffer): Likewise. * db-sort.el (database-sort-interface): Likewise. 2006-06-05 Thien-Thi Nguyen * db-util.el (db-meta-prefix-ify): Delete macro. * db-interfa.el (database-view-mode-map) (database-edit-mode-map): Prefix meta "manually". * db-summary.el (database-summary-mode-map): Likewise. 2006-06-05 Thien-Thi Nguyen * edb.texi (Relational file layout): Write text. 2006-06-05 Thien-Thi Nguyen * edb.texi (Date displaytype, Time displaytype): Merge into parent node. (Predefined displaytypes): Add subsections "Builtin" and "From edb-t-timedate1.el". Expand date and time entries. Add defuns. 2006-06-01 Thien-Thi Nguyen * edb.texi (Predefined record field types): Rewrite intro blurb. Split into subsections "Builtin" and "From edb-t-timedate1.el", each w/ its own blurb. Move performance note for type `date' into edb-t-timedate1.el commentary. 2006-01-17 Thien-Thi Nguyen * GNUmakefile.in (install): Fix omission bug: Also install $(dontcompile) files. 2006-01-17 Thien-Thi Nguyen * skram/GNUmakefile-atvars.in: New file. * skram/GNUmakefile: Include file "GNUmakefile-atvars". (EMACS, topdir): Delete vars. * GNUmakefile.in (skramdist): Add GNUmakefile-atvars.in. * configure.ac: Add AC_CONFIG_FILES entry for "skram/GNUmakefile-atvars". 2006-01-17 Thien-Thi Nguyen * configure.ac (EMACS): If env var by same name has value "t", unset it. Also, use `AC_CHECK_PROG' instead of `AC_PATH_PROG'. 2006-01-07 Thien-Thi Nguyen * db-convert.el: Delete file. * database.el (db-convert): Remove autoload form. * GNUmakefile.in (normal-frags): Remove "convert". 2006-01-07 Thien-Thi Nguyen * lisp/edb-1int-to-single.el: New file. * GNUmakefile.in (normal-lispfrags): New var. (normal): Use $(normal-lispfrags). * skram/GNUmakefile (elisp): Include $(topdir)/lisp/connection.el and $(topdir)/lisp/edb-1int-to-single.el. * edb.texi (Internal file layout): Add @menu. Streamline. Move text into "Internal file layout details". (Internal file layout details): New node/subsection. (edb-1int-to-single): New node/subsection. 2006-01-07 Thien-Thi Nguyen * skram/skram.fmt: Split into three `eval' forms in Local Variables section. 2006-01-06 Thien-Thi Nguyen * lisp/system.el (insert-buffer-substring-no-properties): New func, from GNU Emacs subr.el (CVS revision 1.487). 2006-01-06 Thien-Thi Nguyen * lisp/connection.el (:edb1 :seq-funcs 'read-line): Fix OBOE and ordering lossage; rewrite in tail-pointer style. 2006-01-06 Thien-Thi Nguyen * edb.texi (Invoking EDB): Fix bug: Mention `db-save-database' and `db-write-database-file'. (Example EDB session): Fix gramamr typo. 2006-01-05 Thien-Thi Nguyen * db-convert.el, db-rdb.el, db-search.el, db-sort.el, db-tagged.el: * db-two-dbs.el: Move `provide' form to end of file. 2006-01-04 Thien-Thi Nguyen * db-types.el (define-enum-type): Map `car' over D->A instead of using `all-completions' with empty string first arg. 2006-01-04 Thien-Thi Nguyen * edb.texi (Details of hiding): Remove @defun `dbc-set-hide-p' and intro blurb. Say instead, simply, "when hiding is in effect". 2006-01-04 Thien-Thi Nguyen * db-format.el (dbf-reset-on-edit-list): Delete deflocalvar. (db-edit-mode): Remove `dbf-reset-on-edit-list' processing. * edb.texi (Ongoing migration): Delete @itemx `dbf-reset-on-edit-list'. (Edit mode hooks): Remove @defvar `dbf-reset-on-edit-list'. Merge example with that using `db-edit-mode-hooks'. 2006-01-04 Thien-Thi Nguyen * edb.texi (Manipulating records): Fix typo introduced 2006-01-03. 2006-01-03 Thien-Thi Nguyen * edb.texi (Reading from disk): Remove @defun and refs to `db-setup-data-display-buffer'. Reword appropriately. 2006-01-03 Thien-Thi Nguyen * db-rep.el (record-field): Delete defalias. (record-set-field): Likewise. * edb.texi (Manipulating records): Delete @findex and associated blurbs for `record-field' and `record-set-field'. 2006-01-03 Thien-Thi Nguyen * db-interfa.el (db-commit-record): Delete defalias. * edb.texi (Making changes permanent): Delete @deffnx for `db-commit-record'. (Making additional data display buffers): Use `db-accept-record'. 2006-01-03 Thien-Thi Nguyen * db-rep.el (make-record): Delete defsubst. * edb.texi (Manipulating records): Delete @defun for `make-record'. 2006-01-03 Thien-Thi Nguyen * GNUmakefile.in (EXTRABATCHOPTS, ebatch): New vars. ($(installed-elc-files), installcheck): Use $(ebatch). * skram/GNUmakefile (emacs): Delete var. (EMACS, EXTRABATCHOPTS): New vars. (ebatch): Use $(EMACS) and $(EXTRABATCHOPTS). 2006-01-03 Thien-Thi Nguyen * db-rdb.el (db-rdb-read-fields): Use `string-to-number'. * edb-t-timedate1.el (edb-t-timedate1:parse-time-string): Likewise. 2006-01-03 Thien-Thi Nguyen * db-format.el (dbf-inform-outside-field): Use two-arg variant for `defalias'. 2006-01-01 Thien-Thi Nguyen * autogen.sh (am17): Delete var. (amprefix, amlibdir): New vars. Use `amlibdir' instead of `am17'. 2005-12-31 Thien-Thi Nguyen * configure.ac (AC_INIT): Bump version to "1.26" for release. 2005-12-31 Thien-Thi Nguyen * GNUmakefile.in (cvs-state-summary): Also look at subdir "lisp". 2005-12-31 Thien-Thi Nguyen * edb.texi: Add self as @author. 2005-12-31 Thien-Thi Nguyen * edb.texi: Remove @scadenza{2.x,FOO} entries. Update other @scadenza entries and associated blurbs. 2005-12-31 Thien-Thi Nguyen * db-rep.el (db-record-field): Rename from `record-field'. (record-field): New defalias. (db-record-set-field): Rename from `record-set-field'. (record-set-field): New defalias. (dbf-this-record-set-field): Use `db-record-set-field'. (dbf-displayed-record-field): Use `db-record-field'. * lisp/connection.el (edb--1format-buffer<-connection): Likewise. * edb.texi: Throughout, use `db-record-field' and `db-record-set-field' in examples. (Manipulating records): Say "db-record-field" and "db-record-set-field". Add blurb about `record-field' and `record-set-field' alias. 2005-12-30 Thien-Thi Nguyen * db-rep.el (db-maprecords): Rename from `maprecords'. (maprecords): New defalias. * db-file-io.el (database-stored->actual): Use `db-maprecords'. (db-write-1, db-write-intdelim): Likewise. * db-interfa.el (db-field-query-replace): Likewise. * edb.texi: Throughout, use `db-maprecords' in examples. (Mapping over the database): Say "db-maprecords". Add blurb about `maprecords' alias. 2005-12-29 Thien-Thi Nguyen * edb.texi (The database structure): Delete node/section and refs. (Sort interface): Mention :field-order control property. No longer mention "field-priorities database slot". (Execution of format file eval expressions): No longer mention "fieldnames database slot". (Control properties reference): For :substitution-separators, mention what happens when unspecified. Fix doc for :field-order: Mention `order-function' and `sort-function'. (Specifying a record field type): Mention automatic call via specification of :fields or :tagged-setup. Move @defun for `database-set-fieldnames-to-list' and @vindex and explanation for `db-default-field-type' here. Also, move @defuns here and add @scadenza for `database-recordfieldspec', `database-recordfieldspec-type' and `database-set-recordfieldspec'. (Record field attributes): Say "attribute" instead of "slot". Also, mention :field-order control property instead of "field-priorities database slot". (Resolving ambiguities): Convert examples to show control property usage. Also, mention :substitutions control property instead of "substitutions database slot". (Problems with end-of-file newlines): Convert example to show control property usage. Add @xref "Control properties reference". (Nonregular file layout): Mention :read-record control property instead of "read-record-from-region database slot". No longer mention "record-sepinfo database slot" and "field-sepinfo database slot". Mention :record-separator-function control property. Mention :write-record instead of "write-record-from-region database slot". Add @xref "Control properties reference". (Reading from disk): Reword to not say "database slots". Also, mention :record-FOO and :field-separator control properties instead of "recordsep database slot" and "fieldsep database slot". (Display specifications): Update @pxref. (Auxiliary files): No longer mention "print-name database slot". 2005-12-28 Thien-Thi Nguyen * edb.texi (Kinds of control property values): Add text block example. Convert "regexp cons" to "regexp vector"; document third v element. (Control properties reference): Use "regexp vector". (The sepinfo structure): Delete node/subsection. (Sepinfo examples): Likewise. (How to specify delimited file layout): Rewrite, incorporating some text from the deleted child subsections. 2005-12-28 Thien-Thi Nguyen * lisp/connection.el (:edb1 :schema-schema 'single): Add `string-or-rxvec-p' to :predicates; remove `string-or-rxcons-p'. Use new predicate for :field-separator and :record-separator. (edb--1mm<-connection): Update transforms for changed keys, and add support for contemporaneous :sep-string and regexp specification. 2005-12-25 Thien-Thi Nguyen * db-file-io.el, db-format.el, db-interfa.el, db-rep.el * db-types.el, db-util.el: Don't require `cl'. 2005-12-24 Thien-Thi Nguyen * edb.texi (Designing a database): Delete chapter (node and children). (Specifying control): New chapter (node and children). (Data encoding): New node/section. (Database file layout): Add "Data encoding" to menu. (Sort interface): Add scadenza for `db-sort-modifies-p'. (Changing display formats): Add scadenza and control properties xref for `dbf-format-name-spec-alist'. (Delimited file layout): Say "newlines", not "carriage returns". Also, no longer mention speed disadvantage. (Auxiliary files): Add @scandeza, control properties blurb. (Read hooks): Add @scandeza for `db-before-read-hooks' and `db-after-read-hooks'. (Record display hooks): Add control properties blurb for `dbf-before-display-record-function' (Display format change hooks): Add control properties blurb and scadenza for `db-new-record-function', `dbf-first-change-function' and `dbf-every-change-function'. 2005-12-24 Thien-Thi Nguyen * lisp/connection.el: Make :edb1 :seq-funcs a non-weak hash table. (edb--*schema-schema*): Delete var. Replace an :edb1 init form for :schema-schema followed by init for :edb1 :schema-schema 'single. (edb--validate-schema): Use :edb1 :schema-schema. 2005-12-24 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Fix typo. 2005-12-24 Thien-Thi Nguyen * lisp/connection.el (edb--*sequential-i/o*): Delete var. Replace with an :edb1 init form for :seq-funcs followed by init for :edb1 :seq-funcs 'read-line. (edb--connect): Use :edb1 :seq-funcs. 2005-12-24 Thien-Thi Nguyen * db-sort.el (dbf-hidden-to-end-p): Delete deflocalvar. (dbsi-use-ordering-make-buffer-default): Use :hendp. * database.el: Remove handling for defunct var `dbf-hidden-to-end-p'. * edb.texi (Sort interface): Delete @defvar for `hidden-to-end-p'. 2005-12-23 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Make read-only slots `record-sepinfo' and `field-sepinfo'. * db-nosetf.el (database-set-record-sepinfo) (database-set-field-sepinfo): Delete. 2005-12-23 Thien-Thi Nguyen * lisp/connection.el (edb--1mm<-connection): Elide conversion of vector into list when the result is being passed to `mapcar'. 2005-12-23 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema* single :valid-keys): Specify type predicate for :locals. (edb--1mm<-connection): Transform :locals. 2005-12-23 Thien-Thi Nguyen * db-util.el (db-skip-regexp-backward): Delete defsubst. * db-format.el (db-backward-char): Incorporate deleted defsubst. 2005-12-22 Thien-Thi Nguyen * db-report.el (db-report): Interactively, make :ddb-spec :connection :report override querying for filename. Update filename handling to suit. 2005-12-21 Thien-Thi Nguyen * lisp/connection.el (edb--1format-buffer<-connection): Handle :every-change-function. 2005-12-19 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema* single): Use backquote; unquote lambda expressions. Make :elaborate-value a pair. Likewise for each element of :predicates. (edb--validate-schema): Update `edb--*schema-schema*' access. 2005-12-19 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema* single :valid-keys): Delete :post-last-record. 2005-12-19 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema* single :valid-keys :record-defaults): Specify type predicate. (edb--1format-buffer<-connection): Handle :record-defaults. 2005-12-19 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema* single :predicates): Add `vector-of-two-strings-p'. (edb--*schema-schema* single :valid-keys :substitution-separators): Specify type predicate. 2005-12-18 Thien-Thi Nguyen * db-types.el (define-enum-type enum-do-completions): Fix bug introduced 2005-10-10: Use cdr of `assoc' return value. 2005-12-18 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema* single :valid-keys): Delete :field-setter. 2005-12-18 Thien-Thi Nguyen * lisp/connection.el (edb--1format-buffer<-connection ppcur): Insert additional newline if object is a symbol. (edb--1format-buffer<-connection): Handle :first-change-function. 2005-12-18 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema* single): Specify type predicates for most entries in :valid-keys. Add :elaborate-value and :predicates. (edb--validate-schema): Also elaborate and check types for values. (edb--connect): No longer do value elaboration here. 2005-12-15 Thien-Thi Nguyen * edb.texi: For chapter groups, say "Manual" instead of "Perspective". Throughout, reword to not say "database designer". 2005-12-14 Thien-Thi Nguyen * db-format.el (dbf-format-name-spec-alist): Doc munging; nfc. 2005-12-13 Thien-Thi Nguyen * edb.texi: Convert all @ref to @xref or @pxref. 2005-12-13 Thien-Thi Nguyen * edb.texi (Variables): Delete node. (Exiting Emacs or saving files): Likewise. (In case of trouble): Incorporate deleted nodes as @section. 2005-12-13 Thien-Thi Nguyen * edb.texi (Sort interface): New node/section. (Sorting): Add to menu "Sort interface". 2005-12-13 Thien-Thi Nguyen * edb.texi (Debugging EDB): Delete node/section. 2005-12-12 Thien-Thi Nguyen * db-file-io.el (db-read-file-delimstr): Fix bug introduced 2005-10-20: Use `count'. 2005-12-12 Thien-Thi Nguyen * edb.texi (Bugs in report generation): Delete node/section. 2005-12-12 Thien-Thi Nguyen * edb.texi (Sorting): Document `M-p' and `M-n'. 2005-12-12 Thien-Thi Nguyen * edb.texi (Search patterns): Delete node. (Searching): Incorporate section "Search patterns". 2005-12-12 Thien-Thi Nguyen * edb.texi: Throughout, use @key for RET, DEL and SPC. (Editing a field): Use a table. 2005-12-12 Thien-Thi Nguyen * edb.texi (Exiting database mode): Fix typo. 2005-12-12 Thien-Thi Nguyen * edb.texi (Miscellaneous Ramblings): Remove node/section. (Invoking EDB): Link to "Reading from disk". 2005-12-12 Thien-Thi Nguyen * edb.texi (Example EDB session): Use skram/retired.edb. Emphasize `edb-EXPERIMENTAL-interact'. Say "move point". Convert all @ref to @xref; move them to end of paragraphs. Remove search. Use `x', not `q'; `S', not `M-x db-sort'. Reword support text to describe steps. Rewrite intro. 2005-12-11 Thien-Thi Nguyen * edb.texi: Remove redundant @cindex entries. 2005-12-11 Thien-Thi Nguyen * lisp/connection.el (edb--1mm<-connection): Transform :substitutions. 2005-12-10 Thien-Thi Nguyen * db-file-io.el (database-perform-substitutions): Elide redundant local assignment; nfc. 2005-12-10 Thien-Thi Nguyen * database.el (edb-EXPERIMENTAL-interact): Kludge buffer name for inherent data. 2005-12-10 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema*): Rename :field-priorities to :field-order. (edb--1mm<-connection): Use :field-order; add transform. 2005-12-10 Thien-Thi Nguyen * edb.texi (Miscellaneous Ramblings): New node/section. (Introduction): Add to menu "Miscellaneous Ramblings". (Terminology and concepts): Add Perlis quote and blurb. (Invoking EDB): Add blurb for two approaches. Add @deffn for `edb-EXPERIMENTAL-interact'. Move autoload doc and example into intro blurb. Say "old (1.x only)" for `db-find-file'. 2005-12-09 Thien-Thi Nguyen * edb.texi (Organization of this manual): Mention possibility of implementation deatils disappearing. 2005-12-09 Thien-Thi Nguyen * edb.texi (Terminology and concepts): Rename from "Terminology". Update references. Expand. 2005-12-08 Thien-Thi Nguyen * edb.texi (Naming Conventions): Incorporate nodes "File naming conventions" and "Function and variable naming conventions". Clean up. Add intro blurb. Add section "Type naming conventions". 2005-12-08 Thien-Thi Nguyen * edb.texi (Function and variable naming conventions): Remove defunct entry for variables w/ "dbfs-" prefix. 2005-12-08 Thien-Thi Nguyen * skram/retired.README, skram/retired.edb: New files. 2005-12-07 Thien-Thi Nguyen * lisp/connection.el (edb--1mm<-connection): Add :write-record wrapping. 2005-12-07 Thien-Thi Nguyen * lisp/system.el (help-function-arglist): New func, from GNU Emacs help-fns.el (CVS revision 1.80). * lisp/connection.el (edb--1format-buffer<-connection): Use `help-function-arglist'. 2005-12-07 Thien-Thi Nguyen * GNUmakefile.in (skramdist): Remove retired.fmt. 2005-12-07 Thien-Thi Nguyen * lisp/connection.el (edb--1format-buffer<-connection): Handle :before-display. 2005-12-07 Thien-Thi Nguyen * db-util.el (db-funcall-maybe): Delete func. * db-two-dbs.el (db-merge-records): Incorporate `db-funcall-maybe'. * db-tagged.el (db-tagged-wrfr): Likewise. * db-file-io.el (db-write-intdelim): Likewise. * db-rdb.el (db-rdb-list-wrfr): Likewise. 2005-12-07 Thien-Thi Nguyen * db-format.el (db-display-record): Use `run-hook-with-args'. 2005-12-06 Thien-Thi Nguyen * db-file-io.el (db-read-database-file): Take list of known records as first arg (renamed to SOURCE), in addition to filename. For known-records case, set :file to "(inherent)", :modifiable-p to t, and use `edb--snap!' directly. * database.el (edb-EXPERIMENTAL-interact): Handle case where connection has inherent :data. 2005-12-05 Thien-Thi Nguyen * db-file-io.el (edb-data-coding): Remove defvar. (db-read-database-file): Use `symbol-value' for `edb-data-coding'. 2005-12-05 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema*): Remove :fieldtype, :displaytype and :enumerated-type. (edb--1format-buffer<-connection): Handle :tagged-setup. 2005-12-05 Thien-Thi Nguyen * lisp/connection.el (edb--*schema-schema*): Remove :require. 2005-12-04 Thien-Thi Nguyen * lisp/connection.el (edb--connect): No longer save :unevalled-schema. (edb--1mm<-connection): No longer consult :unevalled-schema nor set :fieldnames and :recordfieldspecs. (edb--1format-buffer<-connection): No longer consult :unevalled-schema. Also, conditionally quote setf forms. 2005-12-04 Thien-Thi Nguyen * db-format.el (db-change-format): Avoid "Reading format..." message for connection-bundled formats. 2005-12-03 Thien-Thi Nguyen * lisp/connection.el (edb--connection-file-cache): New func. (edb--1format-buffer<-connection): Also handle multiple display formats and selecting display format. * db-format.el (db-setup-data-display-buffer): Don't load aux file if TEMPLATE is a buffer. (db-change-format): Dynamically handle "(connection)" file type. 2005-11-28 Thien-Thi Nguyen * lisp/connection.el (edb--connect): Do not eval forms whose car is a string. (edb--1mm<-connection): No longer take second arg PROPERTY. Update caller. Also, use both :unevalled-schema and :schema. Also, fix bug: stuff field-sepinfo w/ proper cruft values. 2005-11-27 Thien-Thi Nguyen * db-file-io.el (db-read-database-file): Accord w/ 2005-10-14 rewrite of `db-kill-buffer-hook': No longer update :ddbufs when killing buffer due to coding-system mismatch. 2005-11-27 Thien-Thi Nguyen * db-format.el (db-setup-ddb-parse-displayspecs): Search entire accessible region for last page (and local-variables block). 2005-11-27 Thien-Thi Nguyen * edb.texi: Remove `(goto-char (point-min))' from `read-record-from-region' functions. Also, reindent @lisp frags and other small cleanup. 2005-11-27 Thien-Thi Nguyen * lisp/connection.el (edb--connect): If arg is a buffer, use its contents. Also, accumulate top-level forms not preceded by a keyword, and eval them in order of appearance after validation. Also, eval the property values of :schema, except where such values are a list w/ keyword first element. Also, save :unevalled-schema. (edb--1mm<-connection): Take optional arg PROPERTY. If specified, use it instead of the connection's :schema property. (edb--1format-buffer<-connection): Use :unevalled-schema for both the generated buffer rewrite and the monolithic-mess stuffing. Also, in the generated buffer, set :connection text property. * database.el (edb-EXPERIMENTAL-interact): Accept buffer as CONTROL, and nil as DATA. If DATA is not specified, search for a file based on CONTROL's filename (or `buffer-file-name' if a buffer). 2005-11-26 Thien-Thi Nguyen * db-format.el (dbf-format-name): Delete deflocalvar. (db-change-format): Use :format-name. Also, if resolved filename of new format is the same as current format's filename, inhibit informative message. * edb.texi (Changing display formats): Remove @defvar for `dbf-format-name'. (Record display hooks): No longer mention `dbf-format-name'. 2005-11-26 Thien-Thi Nguyen * db-file-io.el (db-read-file-custom): Fix bug: When using regexp as record delimiter, set point to beginning of narrowed region prior to calling the read-record-from-region function. 2005-11-24 Thien-Thi Nguyen * lisp/state.el (edb--G, edb--G!): Delete funcs. (edb--arrr!, edb--rinit, edb--rget, edb--rput) (edb--rforget): New funcs. * db-util.el (edb--G, edb--G!): New funcs. (edb--state): Delete deflocalvar. Replace with an :edb1 init form for :bprops. (edb--S, edb--S!): Use :edb1 :bprops. * db-rep.el (:1singles): Update init form syntax. * db-types.el (:1displaytypes, :1recordfieldtypes): Likewise. * db-format.el (:1moving-mark): Update init form syntax. (db-view-mode, dbf-process-field-maybe, db-make-data-display-buffer) (db-additional-data-display-buffer): Use :bprops and `current-buffer'. * db-summary.el (db-summary): Likewise. * db-sort.el (database-sort-interface): Likewise. * db-interfa.el (db-exit): Likewise. (db-kill-buffer-hook): Also remove current buffer from :bprops in :edb1 hash table. * bfuncs (edb-bfunc-make-edbcore): Update syntax for global hash table init forms. Also, output the :edb1 init. 2005-11-23 Thien-Thi Nguyen * db-rep.el (db--mkrec): New func. (db-make-record, make-record): Use `db--mkrec'. * db-file-io.el (db-read-file-custom): Use RRFUNC return value directly if it is a vector, otherwise pass to `db--mkrec'. * db-rdb.el (db-rdb-list-rrfr): Return plist. * db-tagged.el (db-tagged-rrfr): Likewise. * edb.texi (Nonregular file layout): Mention that `db-make-record' usage for `read-record-from-region' is for backward-compatability. Also, remove redundant @cindex entries for `read-record-from-region' and `write-region-from-record'. (Nonregular database example): Update examples to return plist in `read-record-from-region' function. (Manipulating records): Update docs for `db-make-record'. 2005-11-22 Thien-Thi Nguyen * db-tagged.el (db-tagged-p): Delete defsubst. (db-tagged-setup, db-tagged-database-stored->actual) (db-tagged-before-read): Use :tagged-field-spec. * db-rdb.el (db-rdb-p): Delete defsubst. (db-rdb-setup, db-rdb-database-stored->actual): Use :rdb-field-defs. 2005-11-20 Thien-Thi Nguyen * lisp/state.el (edb--hashcollect): Handle :vals for WHAT. 2005-11-20 Thien-Thi Nguyen * db-interfa.el (db-save-database-helper): Delete func. (db-save-database): Incorporate `db-save-database-helper'. Also, use `yes-or-no-p'. 2005-11-19 Thien-Thi Nguyen * edb.texi (Changing display formats): Remove @defvar for `dbf-format-file'. (Execution of format file eval expressions): Remove @defvar for `dbf-always-forms'. Update refs to describe user-visible behavior. (Reading from disk): No longer mention `dbc-database'. (Auxiliary files): Likewise. (Edit mode hooks): Add scadenza for `dbf-reset-on-edit-list'. Also, extend example w/ variant using `db-edit-mode-hooks'. (Display format change hooks): Fix typo. (Database representation): Add @defvar for `dbc-database'. (Manipulating records): Update arglist for `record-set-field'. 2005-11-19 Thien-Thi Nguyen * db-interfa.el (db-kill-buffer-hook): If there are no buffers left, check for and also kill :ddb-spec buffer. * database.el (edb-EXPERIMENTAL-interact): New func. 2005-11-19 Thien-Thi Nguyen * db-format.el (db-setup-data-display-buffer): Make first arg TEMPLATE; extend to handle the case where it is a buffer. * db-file-io.el (db-read-database-file): Make scond arg DISPLAY-TEMPLATE; extend to handle the case where it is a buffer. 2005-11-19 Thien-Thi Nguyen * db-format.el (dbf-format-file): Delete deflocalvar. (db-setup-data-display-buffer, db-change-format): Use :format-file. * db-interfa.el (db-find-file): Use :format-file. 2005-11-19 Thien-Thi Nguyen * db-interfa.el (db-jump-to-record): If ARG is a record, compue and use its index. 2005-11-19 Thien-Thi Nguyen * GNUmakefile.in (edbcore-components, typelibs, normal): Use "substitution references" to construct the value. 2005-11-19 Thien-Thi Nguyen * db-rdb.el (db-rdb-field-name-charset, db-rdb-list-separator-string) (db-rdb-list-entry-regexp, db-rdb-list-continuation-regexp) (db-rdb-list-continuation-output, db-rdb-rrfr-hooks) (db-rdb-wrfr-before-hooks, db-rdb-wrfr-after-hooks) (db-rdb-converted-p, db-rdb-file-type, db-rdb-header-fields) (db-rdb-field-defs, db-rdb-header-string): Delete vars. (db-rdb-p, db-rdb-setup, db-rdb-database-stored->actual) (db-rdb-list-rrfr, db-rdb-list-wrfr, db-rdb-read-fields): Use :rdb-field-defs, :rdb-converted-p, :list-entry-regexp, :list-continuation-regexp, :list-continuation-output, :file-type, :max-field-name-length, :continuation-output, :header-string, :pre-parse-thunk, :pre-write-function, :post-write-function and :header-fields "database-local variables" via `edb--T!' and `edb--T', as well as " | ". 2005-11-19 Thien-Thi Nguyen * GNUmakefile.in (skramdist): New var. (distfiles): Use $(skramdist). 2005-11-19 Thien-Thi Nguyen * db-interfa.el (dbf-finished-sorting): Update summary buffer, whether or not there are windows open on it. 2005-11-19 Thien-Thi Nguyen * lisp/connection.el: New file. * GNUmakefile.in (edbcore-lispfrags): Add "connection". 2005-11-19 Thien-Thi Nguyen * db-sort.el (db-make-ordering-fields-canonical): No longer take OFIELDS; compute it internally. Also, fix omission bug: Handle ignored and repeated conditions. (database-sort-interface): Update call to changed func. 2005-11-19 Thien-Thi Nguyen * db-sort.el (database-sort-interface): Leave point at first significant field. 2005-11-19 Thien-Thi Nguyen * db-sort.el (database-sort): Use current database when DB nil. 2005-11-19 Thien-Thi Nguyen * db-format.el (dbf-this-record): Delete deflocalvar. (dbf-set-this-record-modified-function) (dbf-set-this-record-modified-p, dbf-displayed-record) (dbf-after-record-change-function, dbf-process-field-maybe) (dbf-process-current-record-maybe, db-setup-data-display-buffer) (db-make-data-display-buffer, db-additional-data-display-buffer): Use :under. * db-rep.el (record-field): Use :under. 2005-11-19 Thien-Thi Nguyen * db-format.el (dbf-this-field-text): Use `buffer-substring-no-properties'. 2005-11-19 Thien-Thi Nguyen * db-format.el (dbf-always-forms): Delete deflocalvar. (db-change-format, dbf-always): Use :always-forms. 2005-11-19 Thien-Thi Nguyen * db-rep.el (database-add-record): If LOCATION is a function, call it w/ the current index to compute the new index. 2005-11-19 Thien-Thi Nguyen * db-interfa.el (db-sort): Set :record/before-sorting. (dbf-finished-sorting): Fix bug introduced 2005-10-10: Use previously stored record instead of current (stale) index. 2005-11-19 Thien-Thi Nguyen * db-format.el (dbf-moving-mark): Delete var. (:1moving-mark): New global hash key init form. (db-jump-to-point): Use :1moving-mark in EDB hash. 2005-11-19 Thien-Thi Nguyen * db-rep.el (record-set-field): Make DATABASE optional. If omitted or nil, use `dbc-database'. (dbf-this-record-set-field): No longer pass DATABASE to `record-set-field'. 2005-11-19 Thien-Thi Nguyen * db-rep.el (maprecords): Make DB optional. If omitted or nil, use `dbc-database'. * db-interfa.el (db-field-query-replace): No longer pass DB to `maprecords'. * edb.texi (Setting the mark and hide bits): In examples, no longer specify DB to `maprecords'. (Mapping over the database): Likewise. Also, update @defun for `maprecords'. 2005-11-19 Thien-Thi Nguyen * db-rep.el (record-field): Make DATABASE optional. Also, if RECORD is t, use the "current record". (dbf-displayed-record-field): Omit DATABASE arg to `record-field'. * edb.texi (Nonregular database example) (Record display hooks, Mapping over the database): In examples, don't pass DATABASE to `record-field'. (Manipulating records): Update @defun for `record-field'. 2005-11-19 Thien-Thi Nguyen * db-tagged.el (edb--T, edb--T!): Move from here... * db-rep.el (edb--T, edb--T!): ...to here. 2005-11-18 Thien-Thi Nguyen * db-rep.el (db-make-record): New func. (make-record): Use `db-make-record'. * db-format.el (db-setup-data-display-buffer): Use `make-vector'. (db-make-data-display-buffer): Likewise. (db-additional-data-display-buffer): Likewise. * db-interfa.el (db-add-record): Likewise. * db-two-dbs.el (db-merge-records): Likewise. * db-tagged.el (db-tagged-rrfr): Use `db-make-record'. * db-rdb.el (db-rdb-list-rrfr): Likewise. * edb.texi (Nonregular file layout): Mention `db-make-record'. (Nonregular database example): Use `db-make-record' in examples. (Manipulating records): Add @defun for `db-make-record'. Add scadenza and accompanying blurb for `make-record'. 2005-11-18 Thien-Thi Nguyen * db-sort.el (dbf-field-priorities): Delete deflocalvar. (dbsi-quit-clear-buffer-default) (dbsi-use-ordering-make-database-default) (dbsi-use-ordering-make-buffer-default): Use :field-priorities. * database.el: Remove handling for defunct var `dbf-field-priorities'. * edb.texi (Sorting): No longer mention `dbf-field-priorities'. 2005-11-18 Thien-Thi Nguyen * db-rep.el (edb--v1-rs): Use namespace-conformant :conc-name. (db-rs-sortfunc, db-rs-ordfunc, database-recordfieldspec-type) (db-check-constraint): Update refs to `edb--v1-rs' slots. * db-file-io.el (db-read-file-delimstr) (db-write-intdelim, database-stored->actual): Likewise. * db-interfa.el (db-field-help, db-add-record): Likewise. * db-rdb.el (db-rdb-setup, db-rdb-list-wrfr): Likewise. * db-search.el (db-match): Likewise. * db-tagged.el (db-tagged-setup, db-tagged-wrfr): Likewise. * db-two-dbs.el (db-merge-records, databases-compatible): Likewise. * db-nosetf.el (recordfieldspec-set-type) (recordfieldspec-set-default-value) (recordfieldspec-set-common-form-function) (recordfieldspec-set-merge-function) (recordfieldspec-set-order-fn, recordfieldspec-set-sort-fn) (recordfieldspec-set-match-function, recordfieldspec-set-help-info) (recordfieldspec-set-actual->stored) (recordfieldspec-set-stored->actual) (recordfieldspec-set-constraint-function) (recordfieldspec-set-order-function) (recordfieldspec-set-sort-function): Delete. * edb.texi (Recordfieldspec change hooks): Delete node/subsection. (Predefined record field types): Use "record field type". (Record field attributes): Rename from "The recordfieldspec structure". Also, rephrase intro to use the term "attribute" instead of "slot", and convert items in table from symbol to keyword. Update refs. 2005-11-18 Thien-Thi Nguyen * db-rep.el (edb--v1-rs): Remove unused `change-hook' slot. * db-nosetf.el (recordfieldspec-set-change-hook): Delete. * edb.texi (The recordfieldspec structure): Remove `change-hook' docs. 2005-11-18 Thien-Thi Nguyen * db-format.el (dbf-change-functions): Delete deflocalvar. (dbf-set-change-function): Use :change-functions. (dbf-process-field-maybe, db-setup-data-display-buffer) (db-make-data-display-buffer): Likewise. * edb.texi (Display format change hooks): Remove doc and references for var `dbf-change-functions'. 2005-11-17 Thien-Thi Nguyen * db-convert.el (db-canonicalize-creation-method): Delete func. (db-convert): Incorporate `db-canonicalize-creation-method'. 2005-11-17 Thien-Thi Nguyen * db-util.el (db-message): Don't keep undo info in log buffer. (db-unused-char-in-string): No longer disable undo info. 2005-10-31 Thien-Thi Nguyen * db-format.el (db-dsym): New defconst. (db-dsrx, db-dsrx-fieldname, db-dsrx-fieldoptions) (db-dsrx-content-beginning, db-dsrx-content-end) (db-dsrx-content-end-alt): Delete defconsts. (db-dspec<-string, db-setup-ddb-parse-displayspecs): Use `db-dsym'. * db-summary.el (db-format->lines/sforms): Likewise. 2005-10-31 Thien-Thi Nguyen * db-format.el (db-fopt): New defconst. (db-foptrx, db-foptrx-equals, db-foptrx-symbol): Delete defconsts. (db-dsrx, db-dspec<-type/opts): Use `db-fopt'. 2005-10-31 Thien-Thi Nguyen * db-interfa.el (db-mention-filename-on-save-p): Delete var. (db-save-database-helper, db-write-database-file): Incorporate value of `db-mention-filename-on-save-p'. 2005-10-31 Thien-Thi Nguyen * db-interfa.el (dbc-deleted-record): Delete var. (db-delete-record, db-yank-record): Use :deleted-record in global hash. 2005-10-31 Thien-Thi Nguyen * db-interfa.el (db-delete-record): Fix bug introduced 2005-10-23: Use `dbc-database', not `dbc-deleted-record'. 2005-10-31 Thien-Thi Nguyen * db-convert.el (db-computed-functions): Delete var. (db-convert-compute-field-value): Delete func. (db-convert): Incorporate `db-convert-compute-field-value'. 2005-10-31 Thien-Thi Nguyen * db-format.el (db-dt-leading-comma-optional): Delete var. (db-dtrx): Incorporate value of `db-dt-leading-comma-optional'. 2005-10-31 Thien-Thi Nguyen * db-sort.el (dbsi-this-field-only): Rewrite. 2005-10-31 Thien-Thi Nguyen * edb.texi (Relational file layout): New node/section. (Database file layout): Add "Relational file layout" to menu. 2005-10-31 Thien-Thi Nguyen * db-interfa.el (db-mark-searched-records): Use :sumbuf. * db-summary.el (db-summary-buffer): Delete defsubst. 2005-10-30 Thien-Thi Nguyen * edb.texi (Making changes permanent): Add scadenza for `db-commit-record'. 2005-10-30 Thien-Thi Nguyen * db-tagged.el (db-tagged-tag-chars, db-tagged-pre-tag) (db-tagged-pre-tag-regexp, db-tagged-pre-tag-output) (db-tagged-separator, db-tagged-separator-regexp) (db-tagged-separator-output, db-tagged-continuation) (db-tagged-continuation-regexp, db-tagged-continuation-output) (db-tagged-rrfr-hooks, db-tagged-wrfr-before-hooks) (db-tagged-wrfr-after-hooks, db-tagged-converted-p) (db-tagged-default-field): Delete vars. (edb--T, edb--T!): New defsubsts. (db-tagged-setup, db-tagged-p, db-tagged-database-stored->actual) (db-tagged-before-read, db-tagged-rrfr, db-tagged-wrfr): Use :tag-chars, :pre-tag, :pre-tag-regexp, :pre-tag-output, :separator, :separator-regexp, :separator-output, :continuation, :continuation-regexp, :continuation-output, :pre-parse-thunk, :pre-write-function, :post-write-function, :tagged-converted-p, :default-field and :tagged-field-spec "database-local variables" via `edb--T!' and `edb--T'. * edb.texi (Tagged file layout): Add scadenza for `db-tagged-rrfr-hooks' `db-tagged-wrfr-before-hooks' and `db-tagged-wrfr-after-hooks'. Also, update table of attributes recognized by `db-tagged-setup'. 2005-10-30 Thien-Thi Nguyen * db-tagged.el (db-tagged-database-stored->actual): No longer take arg. 2005-10-29 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Fix bug introduced in last change: skip deletion of `print-name' slot. 2005-10-29 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `file' slot. (database-file): New func. * db-nosetf.el (database-set-file): Delete. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `file'. (db-read-database-file): Use :file in global hash. (db-choose-format-file, db-write-1): Likewise. * db-format.el (db-setup-data-display-buffer): Likewise. (db-make-data-display-buffer): Likewise. * db-two-dbs.el (db-merge): Likewise. * db-interfa.el (db-find-read-in-database): Likewise. (db-revert-database, db-save-database-helper): Likewise. (db-write-database-file, db-output-record-to-db): Likewise. 2005-10-29 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Don't use `kill-sexp'; instead use `delete-region'. Also, collect default format filename into alist under :1CRUFT in global hash. (db-choose-format-file): Use :1CRUFT in global hash for :format-file. (db-write-1): Write out a form for :1CRUFT sub-properties. 2005-10-29 Thien-Thi Nguyen * db-interfa.el (db-select-next-record): Use `message'. 2005-10-28 Thien-Thi Nguyen * edb.texi (Accessing record fields): Remove @node, moving the @subsection up one level under "Manipulating records". 2005-10-28 Thien-Thi Nguyen * db-format.el (db-change-format): Use `insert-file-contents'. 2005-10-28 Thien-Thi Nguyen * db-file-io.el (db-reading-noninternal): Use `db'. (db-read-file-custom): Move `database' dynamic binding up one level. 2005-10-28 Thien-Thi Nguyen * db-file-io.el (db-io-error-p): Delete var. (db-read-database-file, db-read-file-delimstr, db-read-file-delimrx): (database-stored->actual, db-write-1): Use :io-error-p in EDB hash. * db-interfa.el (db-write-database-file): Likewise. 2005-10-28 Thien-Thi Nguyen * db-file-io.el (db-substitution-no-no-string): Delete var. (database-io-setup): Use :substitution-no-no in global hash. (database-acceptable-delimiter-p): Likewise. Also, take first arg DB. Update callers. 2005-10-28 Thien-Thi Nguyen * db-file-io.el (db-jam-si): No longer take STRING and DATABASE. Instead, compute STRING internally. (db-read-file-custom, database-io-setup): Update calls to `db-jam-si'. 2005-10-28 Thien-Thi Nguyen * db-file-io.el (database-check-sepinfo): Delete func. (database-io-setup): Incorporate `database-check-sepinfo'. 2005-10-28 Thien-Thi Nguyen * db-sort.el (database-sort-interface): Use `message'. 2005-10-28 Thien-Thi Nguyen * db-file-io.el (db-file->format-file): Delete func. (db-choose-format-file): Incorporate `db-file->format-file'. 2005-10-28 Thien-Thi Nguyen * skram/GNUmakefile (elisp): Include some files under $(topdir)/lisp. 2005-10-28 Thien-Thi Nguyen * edb.texi (Global variables): Remove doc for `db-databases'. 2005-10-28 Thien-Thi Nguyen * lisp/state.el (edb-tag, edb-tagp, edb-tagx, edb-tag-): Move here from database.el. * db-rep.el (db-inform-interval): Move here from database.el. * db-util.el (db-message, db-warning): Move here from database.el. * database.el (db-inform-interval): Delete defvar. (edb-tag, edb-tagp, edb-tagx, edb-tag-, db-message): Delete funcs. (db-warning): Delete macro. 2005-10-28 Thien-Thi Nguyen * db-file-io.el (db-reading-noninternal): Use `message'. 2005-10-27 Thien-Thi Nguyen * db-types.el (dbm-string-regexp-prefix): Delete defvar. (db-string-match-display->actual): Incorporate its value. (dbm-string-regexp-prefix-string): Delete defvar. (db-string-match-actual->display): Incorporate its value. 2005-10-27 Thien-Thi Nguyen * lisp/state.el (edb--define-child-hash): New macro. * db-rep.el (1D): New edb--define-child-hash. (edb--1all-known-databases): Move here from db-interfa.el. (database-set-modified-p): Use `edb--1D' and `edb--1D!'. (database-set-fieldnames-to-list, database-add-record): Likewise. (database-data-display-buffers): Use `edb--1D'. (database-no-of-records, edb--field-nm2no, db-lmap): Likewise. * db-format.el (db-edit-mode, db-jump-to-point): (db-setup-data-display-buffer): Likewise. (db-additional-data-display-buffer): Use `edb--1D' and `edb--1D!'. (database-mode): Use `edb--meta1D'. * db-file-io.el (db-read-database-file): Use `edb--meta1D', `edb--1D' and `edb--1D!'. (db-read-database-internal-file-layout, db-read-database-file-helper): Use `edb--meta1D' and `edb--1D!'. (db-write-1, db-write-intdelim): Use `edb--1D'. * db-interfa.el (db-kill-all-buffers, db-save-some-buffers, db-find-file): (db-find-read-in-database, db-revert-database, db-save-database): (db-toggle-internal-file-layout, db-toggle-modifiable-p): (dbf-goto-record-internal, db-last-record, dbc-set-index): (db-select-next-record, db-select-first-record, db-select-record): (db-delete-record, db-copy-record, db-output-record-to-db): (dbf-finished-sorting, db-search-field, db-mark-record): (db-hide-record): Use `edb--1D' and sometimes `edb--1D!'. (db-kill-buffer-hook): Use `edb--1D!' and `edb--meta1D'. (edb--1all-known-databases): Move to db-rep.el. * db-summary.el (dbf-fill-summary-buffer, dbf-update-summary-marks): (dbf-update-summary-item, dbs-out-of-date-p, dbs-goto-nth-summary): (dbs-forward-record, dbs-delete-record): Use `edb--1D'. * db-sort.el (database-sort, database-sorted-p, database-ordered-p): (database-sort-interface): Use `edb--1D'. (dbsi-use-ordering-make-database-d): Use `edb--1D!'. * db-two-dbs.el (db-process-two-databases): Use `edb--1D'. (db-merge): Use `edb--1D' and `edb--1D!'. * database.el (edb--databases): Delete func. (edb-tag): Use `edb--1D'. 2005-10-27 Thien-Thi Nguyen * db-util.el (with-selected-window): Move to system.el. * lisp/system.el (with-selected-window): Move here from db-util.el. 2005-10-27 Thien-Thi Nguyen * skram/make-hacksup.el: Ignore non-consp forms. Also, fix bug: if :conc-name is unspecified, include trailing hyphen in generated name. 2005-10-27 Thien-Thi Nguyen * lisp/state.el (edb--hashcollect): New func. * db-interfa.el (edb--1all-known-databases): Use `edb--hashcollect'. 2005-10-27 Thien-Thi Nguyen * lisp/system.el: New file. * GNUmakefile.in (edbcore-lispfrags): Add "system". * database.el: Move `require' form for `edbcore' first. No longer require `cl' or `easymenu'. 2005-10-27 Thien-Thi Nguyen * db-interfa.el (edb--1all-known-databases): New func. (db-save-some-buffers): Use `edb--1all-known-databases'. (db-find-read-in-database, db-output-record-to-db): Likewise. * db-two-dbs.el (db-merge): Likewise. * database.el (edb--databases): Make first arg required. No longer handle the case when its value is nil. 2005-10-26 Thien-Thi Nguyen * lisp/state.el: New file. * GNUmakefile.in (edbcore-lispfrags): New var. (edbcore-dbfrags): Rename from `edbcore-compfrags'. (edbcore-components): Use $(edbcore-lispfrags) and $(edbcore-dbfrags). * database.el (db-databases): Delete var. (edb--databases): Use `edb--global-state'. (db-displaytypes, db-recordfieldtypes): Delete vars. * db-rep.el (:1singles): New global hash key init form. (database-set-fieldnames-to-list): Use :1recordfieldtypes in global hash. * db-file-io.el (db-rfspec<-rftype): Likewise. * db-format.el (db-dspec<-dtype): Use :1displaytypes in global hash. * db-types.el (:1displaytypes, :1recordfieldtypes): New global hash key init forms. (define-displaytype-from-displayspec): Use :1displaytypes in global hash. (define-recordfieldtype-from-recordfieldspec): Use :1recordfieldtypes in global hash. * bfuncs: Require `pp'. (edb-bfunc-make-edbcore): Collect top-level `edb--G!' forms. Insert them at ":further-init edb--global-state". (edb-bfunc-make-all): Don't re-order `installed-el-files' value. * edb.texi: No longer mention `db-recordfieldtypes' or `db-databases'. 2005-10-26 Thien-Thi Nguyen * GNUmakefile.in (dist): Also make subdir "lisp". 2005-10-26 Thien-Thi Nguyen * bfuncs (edb-bfunc-get-GNUmakefile): New func. (edb-bfunc-make-edbcore, edb-bfunc-make-all): Use `edb-bfunc-get-GNUmakefile'. 2005-10-25 Thien-Thi Nguyen * db-summary.el (db-data-display-buffer): Delete defsubst. (db-in-data-display-buffer): Use :data-display-buffer. 2005-10-25 Thien-Thi Nguyen * database.el: Remove "To be autoloaded" from autoloaded funcs' docstrings. 2005-10-25 Thien-Thi Nguyen * db-format.el (edb--1ds): Rename structure from `edb--v1-ds'. No longer specify :conc-name. Update :constructor and :copier. (dbf-this-field-name, db-optspec-list, db-next-field-internal): (db-previous-field-internal, db-first-field-internal): (db-jump-to-point, dbf-this-field-end-pos, db-newline): (dbf-process-field-maybe, db-dspec<-dtype, db-dspec<-string): (db-dspec<-type/opts, db-setup-ddb-parse-displayspecs): (db-display-record, db-ds-printed): Use new names for `edb--1ds' refs. * db-two-dbs.el (db-merge-records): Likewise. * db-search.el (db-parse-match-pattern): (db-print-match-pattern): Likewise. * db-interfa.el (db-field-help, db-field-query-replace): (db-search-field): Likewise. * db-summary.el (db-format->lines/sforms): Likewise. * db-types.el (define-displaytype-from-displayspec): Likewise. * db-nosetf.el (displayspec-set-record-index, displayspec-set-indent): (displayspec-set-min-width, displayspec-set-max-width): (displayspec-set-min-height, displayspec-set-max-height): (displayspec-set-min-bytes, displayspec-set-max-bytes): (displayspec-set-truncation-display-action): (displayspec-set-padding-action, displayspec-set-actual->display): (displayspec-set-display->actual): (displayspec-set-match-actual->display): (displayspec-set-match-display->actual): (displayspec-set-truncation-editing-action): (displayspec-set-reachablep): Delete. 2005-10-25 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `default-format-file' slot. * db-nosetf.el (database-set-default-format-file): Delete. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `default-format-file'. (db-choose-format-file): No longer consult DB's "default format file". * edb.texi (Auxiliary files): No longer mention "default format file". (The database structure): Remove doc for slot `default-format-file'. 2005-10-24 Thien-Thi Nguyen * db-file-io.el (db-read-file-custom): Fix bug introduced 2005-04-10: Dynamically bind `database' around call to "read from region" func. (db-write-1): Likewise, for "write region from record" func. 2005-10-24 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `aux-file' slot. * db-nosetf.el (database-set-aux-file): Delete. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `aux-file'. * db-format.el (db-setup-data-display-buffer): Don't check `aux-file' slot in db. * edb.texi (Auxiliary files): No longer mention `aux-file' slot. (The database structure): Remove doc for slot `aux-file'. 2005-10-24 Thien-Thi Nguyen * edb.texi (Invoking EDB): Update arglist for `db-find-file'. 2005-10-24 Thien-Thi Nguyen * db-sort.el (database-sort-mode-map): Bind `M-n' and `M-p'. 2005-10-24 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `hidden-to-end-p' slot. * db-nosetf.el (database-set-hidden-to-end-p): Delete. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `hidden-to-end-p'. * db-sort.el (dbf-hidden-to-end-p): Update docstring. (dbsi-use-ordering-make-buffer-default): Likewise. (dbsi-use-ordering-make-database-default): Likewise. Also, set :hendp in global hash. (database-sort-interface): Use :hendp in global hash. * edb.texi (The database structure): Remove doc for slot `hidden-to-end-p'. 2005-10-24 Thien-Thi Nguyen * edb.texi (The database structure): Remove doc for slot `no-of-records'. 2005-10-24 Thien-Thi Nguyen * db-sort.el (database-sort-interface): No longer set :sig and :non. Also, use text properties :item and :which. Also, use `dolist'. (db-with-pc, db-with-pc-and-ti): Delete macros. (dbsi-prev-cons): Delete func. (dbsi-format): Take additional arg WHICH. Update callers. Use text properties :item and :which. (dbsi-reformat): Use `save-excursion'. (dbsi-kill-line, dbsi-yank-line): Rewrite. (dbsi-increasing, dbsi-decreasing): Use text property :item. (dbsi-ordering-function, dbsi-sorting-function): Likewise. (dbsi-killed-fields-to-end-maybe): Delete func. (dbsi-ordering<-buffer): New func. (dbsi-use-ordering-make-database-default): Use `dbsi-ordering<-buffer'. (dbsi-use-ordering-make-buffer-default, dbsi-use-ordering): Likewise. (dbsi-this-field-only): Use text property :item. * edb.texi (Sorting): Update "sort interface" example. Also, update docs for `dbsi-kill-line' and `dbsi-yank-line'. 2005-10-23 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `no-of-records' slot. (database-no-of-records): New func. (database-empty-p): Use :nrecords in global hash. (database-add-record, db-lmap): Likewise. * db-nosetf.el (database-set-no-of-records): Delete. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `no-of-records'. (db-read-database-file-helper): Use :nrecords in global hash. (edb--snap!, db-write-intdelim): Likewise. * db-interfa.el (db-last-record, dbc-set-index, db-select-next-record): (db-select-record, db-delete-record): Likewise. * db-summary.el (dbf-fill-summary-buffer, dbs-out-of-date-p): Likewise. * db-two-dbs.el (db-process-two-databases, db-merge): Likewise. * db-sort.el (database-sort): Likewise. 2005-10-23 Thien-Thi Nguyen * GNUmakefile.in (EL-FILES, ELC-FILES): Delete vars. (edbcore-compfrags, edbcore-components, generated, dontcompile): (typelibs-frags, typelibs, normal-frags, normal): (source-el-files, installed-el-files, installed-elc-files): New vars. (all): Depend on $(installed-elc-files). ($(installed-elc-files)): Rename target from `$(ELC-FILES)'. Also, depend on $(source-el-files). Also, disable version control subsystem in emacs command. (install): Use $(installed-el-files) and $(installed-elc-files). (clean): Use $(installed-elc-files). Also, remove $(generated). (TAGS): Use $(source-el-files). (distfiles): Add $(source-el-files) and $(dontcompile). 2005-10-23 Thien-Thi Nguyen * bfuncs (edb-bfunc-make-edbcore): Avoid creating edbcore.el~ (backup file). 2005-10-23 Thien-Thi Nguyen * db-summary.el (db-summary): Use `with-current-buffer'. (dbf-fill-summary-buffer, dbf-update-summary-marks): Likewise. 2005-10-23 Thien-Thi Nguyen * db-rep.el (db-lmap): Fix bug introduced in last change: No longer conditionalize value of `htag'. 2005-10-23 Thien-Thi Nguyen * db-file-io.el (db-read-database-file): Use `with-current-buffer'. 2005-10-23 Thien-Thi Nguyen * db-interfa.el (database-view-mode-map): Remove entries which bind an unmodified character to `undefined'. 2005-10-23 Thien-Thi Nguyen * skram/GNUmakefile (ebatch): Disable version control subsystem. (sk2, sk3, sk4): No longer disable version control system. Also, set name to "SKRAM 2", "SKRAM 3", and "SKRAM 4", respectively. 2005-10-23 Thien-Thi Nguyen * db-rep.el (db-lmap): Accumulate w/ tail pointer. 2005-10-23 Thien-Thi Nguyen * db-file-io.el (database-delete-pre-and-post): Delete func. (db-read-database-file-helper): Incorporate deleted func. 2005-10-23 Thien-Thi Nguyen * db-file-io.el (database-substitute-for-read): Delete func. (db-read-file-delimited): Incorporate `database-substitute-for-read'. 2005-10-23 Thien-Thi Nguyen * db-file-io.el (database-substitute-for-write): Delete func. (db-write-intdelim): Incorporate `database-substitute-for-write'. 2005-10-23 Thien-Thi Nguyen * db-file-io.el (db-confirm-seps): Rename from `database-confirm-fieldsep-and-recordsep'. Also, return a vector instead of a list. (db-confls-fieldsep-bad-p): Delete defsubst. (db-confls-recordsep-bad-p): Likewise. (db-confls-no-of-records): Likewise. (db-conftup-bad-fsep): New defsubst. (db-conftup-bad-rsep, db-conftup-reccount): Likewise. (db-read-file-delimited, db-write-intdelim): Use `db-confirm-seps', `db-conftup-bad-fsep', `db-conftup-bad-rsep' and `db-conftup-reccount'. 2005-10-22 Thien-Thi Nguyen * PLANS: Delete file. * GNUmakefile.in (distfiles): Remove PLANS. 2005-10-22 Thien-Thi Nguyen * db-summary.el (dbf-in-summary-buffer): Delete macro. (dbf-fill-summary-buffer): Use `db-in-buffer'. (dbf-update-summary-marks): Likewise. (dbf-update-summary-item): Likewise. (dbs-out-of-date-p): Use `with-current-buffer'. (dbf-fill-summary-buffer-and-move-to-proper-record): Likewise. * db-format.el (dbf-set-summary-format): Likewise. * db-interfa.el (dbf-finished-sorting): Likewise. (db-add-record): Use `db-in-buffer'. (db-toggle-show-hidden-records): Likewise. 2005-10-22 Thien-Thi Nguyen * db-summary.el (dbs-in-data-display-buffer): Delete macro. (database-summary-mode): Pass buffer to `buffer-name'. (dbs-in-synch-p): Use `with-current-buffer'. (dbs-synch-format-with-summary): Use `db-in-buffer' and `cond'. (dbs-synch-summary-with-format): Use `db-in-buffer'. (dbs-move-to-proper-record): Use `with-current-buffer'. (dbs-next-record-ignore-hiding, dbs-delete-record): Likewise. Also, use `db-in-buffer'. * db-interfa.el (db-next-record): Use `with-current-buffer'. 2005-10-22 Thien-Thi Nguyen * db-interfa.el (dbc-set-hide-p): Rewrite. 2005-10-22 Thien-Thi Nguyen * db-util.el (db-vararg-call): Delete macro. * db-format.el (db-callconvert): New macro. (db-display->actual-call, db-actual->display-call): Delete macros. (dbf-process-field-maybe, db-ds-printed): Use `db-callconvert'. * db-interfa.el (db-field-query-replace): Likewise. * db-two-dbs.el (db-merge-records): Likewise. * db-search.el (db-parse-match-pattern): Likewise. (db-print-match-pattern): Likewise. 2005-10-22 Thien-Thi Nguyen * db-util.el (db-funcall-maybe): Elide redundant `if'. 2005-10-22 Thien-Thi Nguyen * bfuncs: Require `cl'. (edb-bfunc-make-edbcore): New func. (edb-bfunc-make-all): Call `edb-bfunc-make-edbcore'. Also, replace "essential" list w/ "edbcore". * database.el: Replace loading of db-util.el, db-rep.el, db-format.el, db-file-io.el, db-interfa.el, db-types.el and db-summary.el w/ `require' form for `edbcore'. * db-util.el: Remove `provide' form. * db-file-io.el: Don't require `db-rep'. * db-format.el: Don't require `db-rep'. (dbf-set-summary-format): Don't require `db-summary'. * db-rep.el: Don't require `db-util'. Remove `provide' form. * db-summary.el: Remove `provide' form. * edb-t-timedate1.el: Don't require `db-util'. Require `edbcore'. * GNUmakefile.in (ELC-FILES): Remove db-file-io.elc, db-format.elc, db-interfa.elc, db-rep.elc, db-summary.elc, db-types.elc, and db-util.elc. Add edbcore.elc. 2005-10-22 Thien-Thi Nguyen * skram/GNUmakefile (elisp): New var. (hacksup.el, skram.data): Use $(elisp). 2005-10-22 Thien-Thi Nguyen * database.el (db-load-hooks): Delete defvar. Also, no longer run `db-load-hooks' as load-time action. 2005-10-22 Thien-Thi Nguyen * database.el (edb-date): Delete defconst. (edb-version): For this func, incorporate `edb-date' value. 2005-10-22 Thien-Thi Nguyen * bfuncs: New file. * GNUmakefile.in (distfiles): Add bfuncs. ($(ELC-FILES)): Load file bfuncs and call `edb-bfunc-make-all'. * database.el (edb-byte-compile-all): Delete func. (edb-essential-file-names): Delete defconst. Incorporate value in top-level form that references it. 2005-10-21 Thien-Thi Nguyen * db-summary.el (dbf-default-summary-format): Delete defvar. * db-format.el (db-setup-ddb-parse-displayspecs): Use :default-sumfmt. (db-change-format): Likewise. 2005-10-21 Thien-Thi Nguyen * GNUmakefile.in ($(ELC-FILES)): Don't call `batch-byte-compile'. 2005-10-21 Thien-Thi Nguyen * db-util.el (edb--POV): New defvar. (edb-get, edb-put): New funcs. * db-interfa.el (dbc-wraparound-p): Delete deflocalvar. (dbf-stay-in-edit-mode-p): Likewise. (db-next-record): Use :stay-in-edit-mode-p. (db-select-next-record): Use :wraparound-p. * db-format.el (db-setup-data-display-buffer): Move `edb--state' and :fend init from here... (db-make-data-display-buffer): ...to here. Also, init :wraparound-p and :stay-in-edit-mode-p. Use `with-current-buffer'. 2005-10-21 Thien-Thi Nguyen * db-util.el (db-in-buffer): Don't use `get-buffer-create'. 2005-10-20 Thien-Thi Nguyen * db-two-dbs.el (database-compare-hack): Use `with-current-buffer'. * database.el (db-message): Likewise. Also, use `get-buffer-create'. 2005-10-20 Thien-Thi Nguyen * db-interfa.el (dbc-hide-p): Delete deflocalvar. (dbc-set-hide-p, dbc-set-index, db-select-next-record): (db-select-first-record, db-search-field, db-hide-record): (db-hiding-toggle, db-report): Use :hide-p. * db-format.el (database-mode): Likewise. * db-summary.el (database-summary-mode, dbf-fill-summary-buffer): (dbf-update-summary-marks, dbf-update-summary-item): (dbs-move-to-proper-record): Likewise. * database.el: Don't modify `minor-mode-alist'. 2005-10-20 Thien-Thi Nguyen * db-format.el (dbf-inform-outside-field): Make into defalias. (dbf-field-boundary-action): Delete deflocalvar. 2005-10-20 Thien-Thi Nguyen * db-interfa.el (dbc-index): Delete deflocalvar. (db-revert-database, dbf-goto-record-internal, db-next-record): (dbc-set-index, db-select-next-record, db-select-first-record): (db-add-record, db-delete-record, db-yank-record, db-copy-record): (db-output-record-to-db, dbf-finished-sorting, db-field-query-replace): (db-search-field, db-mark-record, db-hide-record, db-unhide-all): (db-unmark-all): Use :index. * db-format.el (dbf-process-current-record-maybe): Likewise. * db-summary.el (db-format->lines/sforms, dbs-move-to-proper-record): (dbs-next-record-ignore-hiding, dbs-delete-record): Likewise. * db-two-dbs.el (db-merge): Likewise. * db-file-io.el (db-reading-noninternal): No longer use `dbc-index'. Instead, use `count' for informative message. (db-read-file-delimstr, db-read-file-delimrx): Use `count' in `db-reading-noninternal' body. 2005-10-18 Thien-Thi Nguyen * db-format.el (dbf-minor-mode): Delete deflocalvar. (dbf-minor-mode-name): Likewise. (database-mode): Set `major-mode' and `mode-name'. Use `database-view-mode' and `database-edit-mode'. (db-view-mode): Likewise. Also, no longer do initial "database mode" check. (db-data-display-buffer-p): Use `database-view-mode' and `database-edit-mode'. * db-interfa.el (db-toggle-modifiable-p): Check `major-mode'; use `database-edit-mode'. * db-summary.el (dbs-edit): Check `major-mode'; use `database-view-mode'. * edb.texi (Database mode hooks): Rename from "Database minor mode hooks". (Database mode): No longer say "minor mode" database submodes. 2005-10-18 Thien-Thi Nguyen * db-interfa.el (dbc-index-fraction): Delete deflocalvar. (dbc-set-index): Use :index-fraction. * db-summary.el (dbs-set-index, database-summary-mode): Likewise. * db-format.el (database-mode): Likewise. 2005-10-17 Thien-Thi Nguyen * db-format.el (database-mode): Set `mode-line-modified'. Use `mode-line-modified' in value for `mode-line-format'. 2005-10-17 Thien-Thi Nguyen * db-interfa.el (database-clean-data-display-buffers): Delete func. (db-save-some-databases, db-find-read-in-database): (db-find-file, db-revert-database): Use :ddbufs from global hash. * db-two-dbs.el (db-merge): Likewise. * db-rep.el (database-set-modified-p): Likewise. 2005-10-17 Thien-Thi Nguyen * skram/skram.fmt, skram/skram.edb: Specify record terminator (two newlines) at EOF. 2005-10-17 Thien-Thi Nguyen * db-format.el (dbf-process-field-maybe): Fix bug: If the field has changed, actually note it as modified. 2005-10-17 Thien-Thi Nguyen * db-util.el (db-copy-buffer-local-variables): Take rest-arg EXCLUDE; don't copy those variables. * db-format.el (db-additional-data-display-buffer): Don't copy `edb--state' from original data display buffer. * db-file-io.el (db-write-1): Don't copy `major-mode' and `buffer-read-only' from original data display buffer. 2005-10-16 Thien-Thi Nguyen * skram/skram.fmt, skram/skram.edb: Move `\kind' to replace "defined" in "defined here". 2005-10-16 Thien-Thi Nguyen * db-format.el (dbf-process-field-maybe): Use `cond'. 2005-10-16 Thien-Thi Nguyen * db-interfa.el (db-toggle-modifiable-p): Force mode-line update. 2005-10-16 Thien-Thi Nguyen * db-format.el (dbf-format-file-spec-alist): Delete deflocalvar. (db-change-format): Use :fmtspec-stash. 2005-10-16 Thien-Thi Nguyen * db-rep.el (record-field-from-index): Delete defsubst. (record-field): Use `aref'. (record-set-field-from-index): Delete defsubst. (record-set-field): Use `db-check-constraint' and `aset'. * db-interfa.el (db-field-query-replace): Likewise. * db-format.el (dbf-process-field-maybe): Likewise. * edb.texi (Accessing record fields): Remove blurb associated with `record-field-from-index' and `record-set-field-from-index'. 2005-10-16 Thien-Thi Nguyen * db-two-dbs.el (db-merge-records): Use `aset' instead of `record-set-field-from-index' with nil fourth argument. * db-interfa.el (db-add-record): Likewise. * db-file-io.el (db-read-file-delimstr): (db-read-file-delimrx, database-stored->actual): Likewise. 2005-10-16 Thien-Thi Nguyen * edb.texi: Convert some @example blocks to @lisp. Munge lisp code to reduce line width, where necessary. 2005-10-16 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Set :nm2no in global hash. * db-rep.el (database-set-fieldnames-to-list): Likewise. (edb--field-nm2no): No longer set :nm2no in global hash here. 2005-10-16 Thien-Thi Nguyen * database.el (db-databases): Use `eq' for hash :test. 2005-10-16 Thien-Thi Nguyen * db-rdb.el (db-rdb-read-fields): Use `with-current-buffer'. 2005-10-16 Thien-Thi Nguyen * db-util.el (db-in-buffer): Expand BODY only once. 2005-10-16 Thien-Thi Nguyen * db-util.el (db-best-fit-message): Delete func. * db-interfa.el (db-field-help): Use `message'. * database.el (db-message): Likewise. 2005-10-16 Thien-Thi Nguyen * db-interfa.el (db-report): Use `with-temp-buffer'. (db-revert-database): Use `with-current-buffer'. 2005-10-16 Thien-Thi Nguyen * db-file-io.el (db-read-database-file-helper): No longer take arg BUF; instead, read from current buffer. Also, no longer kill the buffer when done. (db-read-database-file): Use `with-temp-buffer'. Also, update call to `db-read-database-file-helper'. * db-interfa.el (db-revert-database): Use `with-temp-buffer'. Also, update call to `db-read-database-file-helper'. * db-format.el (db-setup-data-display-buffer): Use `with-current-buffer'. 2005-10-16 Thien-Thi Nguyen * db-summary.el (database-summary-mode): Don't turn off auto-save-mode. Don't set buffer-local var `buffer-file-name'. * db-sort.el (database-sort-interface-mode): Likewise. * db-format.el (database-mode): Likewise. 2005-10-15 Thien-Thi Nguyen * db-interfa.el (database-view-mode-map): Bind `+' to `db-additional-data-display-buffer'. * edb.texi (Making additional data display buffers): Mention `db-additional-data-display-buffer' keymap binding. 2005-10-15 Thien-Thi Nguyen * db-file-io.el (db-write-1): Use `with-temp-buffer'. Also, no longer accept args. Instead, derive auto vars from the current buffer and its state. * db-interfa.el (db-write-database-file): Call `db-write-1' w/ no args. 2005-10-15 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `data-display-buffers' slot. (database-data-display-buffers): New func. * db-nosetf.el (database-set-data-display-buffers): Delete. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `data-display-buffers'. (db-write-1): Drop handling for `data-display-buffers' slot. (db-read-database-file): Use :ddbufs in global hash. * db-format.el (db-additional-data-display-buffer): Likewise. * db-two-dbs.el (db-merge): Likewise. * db-interfa.el (db-kill-all-buffers, db-kill-buffer-hook): (db-find-file, database-clean-data-display-buffers): Likewise. * edb.texi (The database structure): Remove `data-display-buffers'. (Internal file layout): No longer mention removed slot. 2005-10-15 Thien-Thi Nguyen * db-format.el (db-display-record): Fix bug introduced 2005-10-11: Set auto vars `displayspecs', `len', and `iftxt' after calling `dbf-before-display-record-function' in case it changes things. 2005-10-15 Thien-Thi Nguyen * db-interfa.el (dbc-update-database-modified-p): (dbc-set-database-modified-p): Delete defsubst and calls. (db-save-database): Use :modp in global hash. (db-delete-record, db-yank-record): Use `database-set-modified-p'. * db-rep.el (database-set-modified-p): No longer use :dbmodp. * db-file-io.el (db-write-1): Don't call `dbc-update-database-modified-p'. * db-format.el (dbf-process-current-record-maybe): Use `database-set-modified-p'. (db-display-record): Don't call `dbc-update-database-modified-p'. (database-mode): For mode line, use :modp in global hash. 2005-10-15 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `modified-p' slot. (database-set-modified-p): Use :modp in global hash. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `modified-p'. (db-write-1): Drop `modified-p' handling for "internal format". * db-interfa.el (dbc-update-database-modified-p): Use :modp in global hash. * edb.texi (The database structure): Remove `modified-p' docs. 2005-10-15 Thien-Thi Nguyen * db-summary.el (dbs-quit): New func. (database-summary-mode-map): Bind `q' to `dbs-quit'. (database-summary-mode-menu): Add entry for "Quit". 2005-10-15 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `modifiable-p' slot. * db-nosetf.el (database-set-modifiable-p): Delete. * db-format.el (db-edit-mode): Use :modifiable-p in global hash. * db-interfa.el (db-toggle-modifiable-p): Likewise. * db-file-io.el (db-read-database-file): Likewise. (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `modifiable-p'. * edb.texi (The database structure): No longer mention `modifiable-p' slot or its associated `db-toggle-modifiable-p'. (Database Edit mode): Add blurb on "modfiable" state, and move @deffn for `db-toggle-modifiable-p' here. 2005-10-15 Thien-Thi Nguyen * db-summary.el (dbf-summary-show-hidden-records-p): Delete deflocalvar. (dbf-fill-summary-buffer, dbf-update-summary-marks): (dbf-update-summary-item, dbs-move-to-proper-record): (dbs-next-record-ignore-hiding): Use :invisible-hidden-p. * db-interfa.el (db-hiding-toggle): Use :invisible-hidden-p. (db-toggle-show-hidden-records): Likewise. * edb.texi (Database Summary mode): No longer mention and remove @defvar for `dbf-summary-show-hidden-records-p'. Add @ref "Details of hiding". 2005-10-14 Thien-Thi Nguyen * db-interfa.el (db-kill-buffer-hook-inhibit-p): Delete defvar. (database-view-mode-map): Bind `x' and `X' to `db-kill-buffer' and `db-kill-all-buffers', respectively. (db-kill-buffer, db-kill-all-buffers): New funcs. (db-exit): Use `db-kill-all-buffers'. (db-kill-buffers): Delete func. (db-kill-buffer-hook): Rewrite. * edb.texi (Exiting database mode): Move @deffn for `db-exit' after table. Add blurb and scadenza for `db-exit'. Add @deffn for `db-kill-buffer' under item `x'. Add new item `X' with @deffn for `db-kill-all-buffers'. Remove @defun for `db-kill-buffers'. 2005-10-14 Thien-Thi Nguyen * db-summary.el (dbs-exit): Kill the summary buffer. Also, use `pop-to-buffer' to return to the data display buffer. 2005-10-14 Thien-Thi Nguyen * db-format.el (db-additional-data-display-buffer): Fix omission bug: initialize `edb--state' in new buffer. 2005-10-14 Thien-Thi Nguyen * db-summary.el (dbf-summary-buffer): Delete defsubst. (dbf-in-summary-buffer, db-summary-buffer, db-summary): (dbf-fill-summary-buffer): Use :sumbuf. * db-interfa.el (db-quit, dbf-finished-sorting): Use :sumbuf. 2005-10-14 Thien-Thi Nguyen * db-summary.el (dbf-summary-buffer): Delete deflocalvar. (dbf-summary-buffer, dbf-in-summary-buffer, db-summary): (dbs-synch-format-with-summary): Use :sumbuf. * db-interfa.el (db-add-record): Use :sumbuf. 2005-10-14 Thien-Thi Nguyen * db-summary.el (dbf-make-summary-maker): Delete func. * db-format.el (dbf-set-summary-format): Incorporate deleted func. 2005-10-14 Thien-Thi Nguyen * db-summary.el (dbf-summary-format): Delete deflocalvar. (db-summary): Use :sumfmt. * db-format.el (db-setup-ddb-parse-displayspecs): Use :sumfmt. (db-change-format, dbf-set-summary-format): Likewise. 2005-10-13 Thien-Thi Nguyen * db-summary.el (dbf-summary-function): Delete deflocalvar. (db-summary, dbf-fill-summary-buffer): (dbf-update-summary-item, dbf-make-summary-maker): Use :sumfun. * db-format.el (db-change-format): Likewise. 2005-10-13 Thien-Thi Nguyen * db-format.el (dbf-make-format-spec): Delete func. (db-change-format): Incorporate `dbf-make-format-spec'. 2005-10-13 Thien-Thi Nguyen * db-util.el (edb--state): New deflocalvar. (edb--S, edb--S!): New defsubsts. * db-rep.el, db-interfa.el, db-two-dbs.el: Throughout, use `edb--S' and `edb--S!' instead of `edb--DD' and `edb--DD!'. * db-sort.el: Throughout, use `edb--state', `edb--S' and `edb--S!' instead of `edb--dd-internals', `edb--DD" and `edb--DD!'. * db-format.el: Throughout, use `edb--state', `edb--S' and `edb--S!' instead of `edb--dd-internals', `edb--DD" and `edb--DD!'. (edb--dd-internals): Delete deflocalvar. (edb--DD, edb--DD!): Delete defsubsts. * db-summary.el: Throughout, use `edb--state', `edb--S' and `edb--S!' instead of `edb--dd-internals', `edb--DD" and `edb--DD!'. (edb--summary-internals): Delete deflocalvar. (edb--S, edb--S!): Delete defsubsts. 2005-10-13 Thien-Thi Nguyen * db-search.el (dbf-field-search-defaults): Delete deflocalvar. * database.el: Remove handling for defunct `dbf-field-search-defaults'. * db-interfa.el (db-search-field): Use :search-defaults. * db-format.el (dbf-make-format-spec): Likewise. (db-setup-ddb-parse-displayspecs): Init :search-defaults. (db-change-format): Use :search-defaults. 2005-10-13 Thien-Thi Nguyen * db-summary.el (database-summary-mode-map): Fix bug: Bind "o" to `db-output-record-to-db'. 2005-10-13 Thien-Thi Nguyen * db-interfa.el (db-output-record-to-db): Use global hash for :db-for-output. Fix omission bug: Save new selection. Also, use `with-current-buffer'. 2005-10-13 Thien-Thi Nguyen * database.el (edb--databases): Add handling for :forget MVAL. * db-interfa.el (db-kill-buffers): Explicitly forget `dbc-database'. 2005-10-12 Thien-Thi Nguyen * db-sort.el (dbsi-data-display-buffer): Delete deflocalvar. (dbsi-database, dbsi-killed-fields, dbsi-sig-fields): (dbsi-nonsig-fields, dbsi-hidden-to-end-p): Likewise. (database-sort-interface): Use `dbc-database', :ddb, :hendp, :killed, :sig and :non. (database-sort-interface-mode): Docstring munging; nfc. (dbsi-prev-cons): Use :sig and :non. (dbsi-format): Use `dbc-database'. (dbsi-kill-line, dbsi-yank-line): Use :killed. (dbsi-toggle-hidden-to-end): Use :hendp. (dbsi-quit, dbsi-quit-clear-buffer-default): Use :ddb. (dbsi-killed-fields-to-end-maybe): Use :killed and :non. (dbsi-use-ordering-make-database-default): Use :ddb, :sig, :non, :hendp and `dbc-database'. (dbsi-use-ordering): Use `dbc-database', :ddb, :sig and :hendp. (dbsi-this-field-only): Use `dbc-database'. 2005-10-12 Thien-Thi Nguyen * db-interfa.el (db-for-output): Delete deflocalvar. (db-output-record-to-db): Use :db-for-output. 2005-10-12 Thien-Thi Nguyen * db-interfa.el (dbc-database-modified-p): Delete deflocalvar. (dbc-update-database-modified-p): Use :dbmodp. (dbc-set-database-modified-p): Likewise. (db-save-database): Likewise. * db-rep.el (database-set-modified-p): Likewise. * db-format.el (database-mode): Use :dbmodp for `mode-line-format'. 2005-10-12 Thien-Thi Nguyen * db-format.el (dbf-inform-outside-field): Use `case'. 2005-10-12 Thien-Thi Nguyen * db-format.el (dbf-this-record): Docstring munging; nfc. (dbf-this-record-modified-p): Delete deflocalvar. (database-mode): Use :eval form w/ :utkmodp for `mode-line-format'. (dbf-set-this-record-modified-p, dbf-displayed-record): (dbf-process-field-maybe, dbf-process-current-record-maybe): (db-revert-record): Use :utkmodp. * db-interfa.el (db-kill-buffer-hook, db-revert-database): Likewise. 2005-10-12 Thien-Thi Nguyen * db-format.el (dbf-this-record-original): Delete deflocalvar. (dbf-set-this-record-modified-p, dbf-displayed-record): (dbf-process-current-record-maybe): Use :original. * db-interfa.el (dbf-goto-record-internal): Init :original. 2005-10-12 Thien-Thi Nguyen * db-format.el (dbf-fields-displayed): Delete deflocalvar. (dbf-make-format-spec, db-next-field-internal, db-display-record): (db-previous-field-internal, dbf-process-field-maybe): Use :shown. (db-setup-ddb-parse-displayspecs, db-change-format): Init :shown. 2005-10-12 Thien-Thi Nguyen * db-format.el (edb--dd-internals): New deflocalvar. (edb--DD, edb--DD!): New defsubsts. (dbf-inter-field-text): Delete deflocalvar. (dbf-recordindex-displayspecno-vector): Likewise. (dbf-this-displayspec): Likewise. (dbf-this-field-index): Likewise. (dbf-this-field-name): Take arg THIS-DS. (dbf-this-field-text): Use :fbeg. (dbf-set-this-field-text): Likewise. (dbf-this-field-beginning-pos): Delete deflocalvar. (dbf-this-field-end-marker): Likewise. (dbf-enter-field-hook): Docstring munging; nfc. (db-view-mode): Set :this-fidx and :this-ds. (db-parse-buffer-error): Add call to `debug', but commented out. (db-next-field, db-previous-field): Use :fbeg. (db-next-field-internal, db-previous-field-internal): Use :displayspecs, :iftxt, and :this-fidx. Set :this-fidx, :this-ds, :fbeg and :fend. (db-first-field-internal): Use and set :this-fidx. Use :iftxt and :displayspecs. (db-jump-to-point): Use :this-fidx, :fbeg, :displayspecs, and :this-ds. (dbf-this-field-end-pos): Use :fend. (dbf-this-field-beginning-pos): Delete unused defsubst. (dbf-this-field-indent): Use :this-ds and :fbeg. (dbf-check-if-outside-field, db-beginning-of-field): Use :fbeg. (db-newline): Use :this-ds and :fbeg. (dbf-process-field-maybe): Make into a defun. Use :this-fidx, :fbeg, and :this-ds. (db-revert-field): Use :this-ds, :this-fidx. Use `unless'. (db-setup-data-display-buffer): Init `edb--dd-internals' and :fend. (db-setup-ddb-parse-displayspecs): Set :iftxt, :displayspecs and :fidx2dsidx. (db-change-format): Likewise. Also use them. (db-emergency-restore-format): Use :this-fidx. (db-display-record): Use :displayspecs and :iftxt. * db-interfa.el (db-field-help): Use :this-ds. (db-next-record): Use :this-fidx. (db-beginning-of-field-or-record): Use :fbeg. (db-field-query-replace): Use :this-fidx, :iftxt and :this-ds. (db-search-field): Use :this-fidx and :this-ds. * db-two-dbs.el (db-merge-records): Use :displayspecs. 2005-10-12 Thien-Thi Nguyen * db-format.el (db-previous-field-internal): Fix bug: Arrange to signal "didn't find before" parse error under the right condition. 2005-10-12 Thien-Thi Nguyen * skram/skram.fmt: Add "(defined here)" to static text. * skram/skram.edb: Likewise. 2005-10-12 Thien-Thi Nguyen * db-format.el (dbf-default-field-face): Delete unused deflocalvar. (dbf-default-inter-field-face, dbf-selected-field-face): Likewise. 2005-10-12 Thien-Thi Nguyen * db-rep.el (database-add-record, db-lmap): Use `dotimes'. 2005-10-12 Thien-Thi Nguyen * db-format.el (dbf-fieldname->displayspecno): Delete unused func. 2005-10-11 Thien-Thi Nguyen * db-file-io.el (database-stored->actual): Use `dotimes'. (db-write-intdelim): Likewise. * db-format.el (db-setup-ddb-parse-displayspecs): Likewise. (db-display-record): Likewise. * db-sort.el (db-make-ordering-fields-canonical): Likewise. * db-two-dbs.el (db-merge-records): Likewise. 2005-10-11 Thien-Thi Nguyen * db-format.el (dbf-displayspecs-length): Delete deflocalvar. (dbf-displayspecs): Docstring munging; nfc. (db-next-field-internal): Use length of `dbf-displayspecs' directly. (db-previous-field-internal, db-jump-to-point): (db-setup-ddb-parse-displayspecs, db-change-format): (db-display-record): Likewise. 2005-10-11 Thien-Thi Nguyen * db-summary.el (database-summary-mode): Left-justify database name in mode-line. 2005-10-11 Thien-Thi Nguyen * db-summary.el (dbf-summary-recompute-all-p): Delete deflocalvar. (dbf-fill-summary-buffer): No longer check or clear deleted var. * db-format.el (dbf-set-summary-format): Clear :summaries local hash directly. 2005-10-11 Thien-Thi Nguyen * db-summary.el (dbs-index-fraction): Delete deflocalvar. (dbs-set-index): Make into a defun. Also, set `dbc-index-fraction' directly. (database-summary-mode): Use `dbc-index-fraction' in mode line. 2005-10-11 Thien-Thi Nguyen * db-summary.el (dbs-index): Delete deflocalvar. (dbs-set-index): Set :index in local hash. (dbf-fill-summary-buffer): Likewise. (dbf-update-summary-item): Use `(edb--S :index)'. (db-format->lines/sforms): Likewise. (dbs-synch-format-with-summary): Likewise. * db-interfa.el (db-next-record): Use `(edb--S :index)'. 2005-10-11 Thien-Thi Nguyen * db-summary.el (dbs-data-display-buffer): Delete deflocalvar. (dbs-in-data-display-buffer): Use `(edb--S :data-display-buffer)'. (db-data-display-buffer, dbs-view, dbs-edit, dbs-exit): Likewise. (db-summary): Likewise. Also, init :data-display-buffer. * db-interfa.el (db-next-screen-or-record, db-add-record): (db-previous-screen-or-record): Use `(edb--S :data-display-buffer)'. 2005-10-11 Thien-Thi Nguyen * db-summary.el (dbfs-lines): Delete deflocalvar. (dbf-fill-summary-buffer): Use :sum1lines from global hash. Also, remove spurious re-init of :sum1lines. (dbf-update-summary-marks): Use :sum1lines from global hash. (dbf-update-summary-item): Likewise. (dbf-make-summary-maker): Set :sum1lines in global hash. (dbs-goto-nth-summary): Use :sum1lines from global hash. (dbs-forward-record, dbs-delete-record): Likewise. * db-format.el (db-jump-to-point): Likewise. 2005-10-11 Thien-Thi Nguyen * database.el (edb-tag): Rename from `edb--db-tag'. Add docstring. (edb-tagp): Likewise, from `edb--tagp'. (edb-tagx): Likewise, from `edb--tagx'. (edb-tag-): Likewise, from `edb--tag-'. * db-rep.el (db-lmap): Use `edb-tag' and `edb-tagp'. * db-interfa.el (dbc-set-index): Use `edb-tagp' and `edb-tag'. (db-select-next-record): Likewise. (db-select-first-record): Likewise. (db-report): Likewise. (db-search-field): Likewise, and also `edb-tagx'. (db-mark-record): Likewise, and also `edb-tag-'. (db-hide-record, db-hide-unmarked-records): (db-mark-unhidden-records, db-unhide-all, db-unmark-all): Likewise. * db-summary.el (dbs-insert-record-summary): Use `edb-tagp'. (dbf-fill-summary-buffer): Use `edb-tag'. (dbf-update-summary-marks): Use `edb-tagp' and `edb-tag'. (dbf-update-summary-item): Likewise. * edb.texi (Setting the mark and hide bits): Add @defun for `edb-tag', `edb-tagp', `edb-tagx' and `edb-tag-', plus example. 2005-10-10 Thien-Thi Nguyen * db-file-io.el (db-write-1): Copy `db', clear some of its slots and write the copy. Also, collapse canonical field-priorities. 2005-10-10 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Canonicalize field-priorities if necessary. 2005-10-10 Thien-Thi Nguyen * db-file-io.el (db-read-database-file-helper): Delete spurious message. 2005-10-10 Thien-Thi Nguyen * db-interfa.el (dbc-record): Delete deflocalvar. (dbf-goto-record-internal): Compute current record from index. (db-select-first-record, db-delete-record, db-copy-record): (db-output-record-to-db, dbf-finished-sorting, db-search-field): (db-mark-record, db-hide-record): Likewise. (db-select-next-record): No longer set `dbc-record'. (db-unhide-all, db-unmark-all): Update call to `dbc-set-index'. 2005-10-10 Thien-Thi Nguyen * db-interfa.el (db-select-record): Throw error if index out of range. 2005-10-10 Thien-Thi Nguyen * database.el (edb--db-tag, edb--tagp, edb--tagx, edb--tag-): New funcs. * db-rep.el (edb--markedp, edb--markedp!, edb--hiddenp, edb--hiddenp!): Delete funcs and associated defsetf forms. (db-lmap): Use `edb--db-tag' and `edb--tagp'. * db-interfa.el (dbc-set-index): Use `edb--tagp' and `edb--db-tag'. (db-select-next-record): Likewise. (db-select-first-record): Likewise. (db-report): Likewise. (db-search-field): Use `edb--db-tag' and `edb--tagx'. (db-mark-record, db-hide-record, db-hide-unmarked-records): (db-mark-unhidden-records, db-unhide-all, db-unmark-all): Likewise, and also `edb--tagp' and `edb--tag-'. * db-summary.el (dbs-insert-record-summary): Take additional args MTAG and HTAG. Also, use `edb--tagp'. (dbf-fill-summary-buffer): Update call to `dbs-insert-record-summary'. (dbf-update-summary-marks): Use `edb--db-tag' and `edb--tagp'. (dbf-update-summary-item): Likewise. Also, update call to `dbs-insert-record-summary'. 2005-10-10 Thien-Thi Nguyen * db-interfa.el (db-select-next-record): Fix bug introduced 2005-10-08: Set `dbc-record' based on new index, not on old. 2005-10-08 Thien-Thi Nguyen * database.el (edb--databases): Use weak-key hash for :markedp and :hiddenp. 2005-10-08 Thien-Thi Nguyen * db-interfa.el (db-select-prev-record): Delete unused defsubst. (db-select-last-record): Likewise. 2005-10-08 Thien-Thi Nguyen * db-rep.el (edb--v1-link): Delete defstruct. (db-new-link): Delete func. (db-next-link-and-index): Delete func. (database-add-record): Add record directly. (db-lmap): Rename internal var `link' to `lmaprecord'; nfc. (maprecords): Rename internal var `ln' to `record'; nfc. * db-interfa.el (dbc-link): Delete deflocalvar. (dbc-record): New deflocalvar. (dbc-index): Update docstring; nfc. (dbf-goto-record-internal): Use `dbc-record'. (dbc-set-index): Take optional arg `record'. If omitted, compute from given index. Also, use the record directly. (db-select-next-record): Rename first arg to `n'. Also, incorporate `db-next-link-and-index' and fix its bugs. (db-select-first-record, db-select-last-record): Use `dbc-record'. (db-delete-record): Likewise. Also, fix bug: Compute new `dbc-index' using modulo. (db-output-record-to-db): Use `dbc-record'. (dbf-finished-sorting): Rename internal var; nfc. (db-search-field): Likewise. Also, pass second arg to `db-set-index'. (db-mark-record): Use `dbc-record'. No longer pass second arg to `dbf-update-summary-item'. Pass second arg to `dbc-set-index'. (db-hide-record): Likewise. (db-hide-unmarked-records, db-report): Rename internal var; nfc. (db-mark-unhidden-records): Likwise. (db-unhide-all, db-unmark-all): Likewise. Also, pass second arg to `dbc-set-index'. * db-file-io.el (database-set-links-from-list): Delete func. (edb--snap!): New func. (db-read-database-file-helper): Use `edb--snap!'. (db-reading-noninternal): Likewise. * db-format.el (dbf-process-current-record-maybe): No longer pass second arg to `dbf-update-summary-item'. * db-summary.el (dbs-insert-record-summary): Rename from `dbs-insert-link-summary'. Rename internal vars. (dbf-update-summary-item): No longer take second arg. Also, compute record from index and use it directly. (dbs-move-to-proper-record): Rename internal var; nfc. * db-sort.el (database-sort): Use `edb--snap!'. Also, use records directly. (database-sorted-p, database-ordered-p): Use records directly. * db-convert.el (db-convert): Use records directly. Also, rename internal var; nfc. * db-two-dbs.el (db-process-two-databases): Use records directly. * edb.texi: No longer mention "links". (The link strucutre): Delete node/subsection. 2005-10-06 Thien-Thi Nguyen * edb.texi (Reading from disk): No longer mention "backward links". (Database representation): Update docs for link collection and contents representation. (The link structure): Remove slots: prev, next, hiddenp, markedp. 2005-10-06 Thien-Thi Nguyen * db-convert.el (db-convert-record): Delete func. (db-convert): Incorporate `db-convert-record'. 2005-10-06 Thien-Thi Nguyen * db-rep.el (database-empty-p): Use `database-no-of-records'. (edb--v1-link): Remove `prev' and `next' slots. (db-join-links): Delete func. (db-next-link-and-index): Use `%' to effect circularity. (database-add-record): Rewrite. (db-lmap): Use `do' to iterate index over vector. * db-nosetf.el (link-set-prev, link-set-next): Delete. * db-file-io.el (database-set-links-from-list): Rewrite. (db-reading-noninternal): Use `database-set-links-from-list'. * db-interfa.el (db-select-first-record): Update access to :vov. (db-select-last-record): Likewise. (db-delete-record): Likewise, and also for :vov update. * db-summary.el (dbf-update-summary-item): Update access to :vov. * db-sort.el (database-sorted-p): Use :vov property in global hash. (database-ordered-p): Likewise. * db-two-dbs.el (db-process-two-databases): Update access to :vov and iteration-termination condition. 2005-10-05 Thien-Thi Nguyen * db-rep.el (edb--v1-link): Remove `markedp' and `hiddenp' slots. (edb--markedp, edb--markedp!): New funcs, made into a setf pair. (edb--hiddenp, edb--hiddenp!): Likewise. (db-next-link-and-index): Use `edb--markedp' and `edb--hiddenp'. (db-lmap): Use `edb--hiddenp'. * db-nosetf.el (link-set-markedp, link-set-hiddenp): Delete. * database.el (edb--databases): Init :markedp and :hiddenp metainfo. * db-interfa.el (dbc-set-index): Use `edb--markedp' and `edb--hiddenp'. (db-select-first-record, db-search-field, db-mark-record): (db-hide-record, db-hide-unmarked-records, db-mark-unhidden-records): (db-unhide-all, db-unmark-all, db-report): Likewise. * db-summary.el (dbs-insert-link-summary): (dbf-update-summary-marks, dbf-update-summary-item): Likewise. 2005-10-05 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove `first-link' slot. (database-set-modified-p): Use `:vov' property in global hash. (db-next-link-and-index, db-lmap): Likewise. (database-add-record): Set and use `:vov' property in global hash. * db-nosetf.el (database-set-first-link): Delete. * db-interfa.el (db-select-first-record, db-select-last-record): Use `:vov' property in global hash. (db-delete-record): Set and use `:vov' property in global hash. * db-summary.el (dbf-update-summary-item): Use `:vov' property in global hash. * db-two-dbs.el (db-process-two-databases): Use `:vov' property in global hash. (db-merge): Set and use `:vov' property in global hash. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, remove slot `first-link'. (database-set-links-from-list): Set and use `:vov' property in global hash. (db-reading-noninternal): Set `:vov' property in global hash. (db-write-1): Remove `first-link' special handling. * edb.texi (Internal file layout): No longer mention `first-link' slot. (Database representation): Likewise. (The database structure): Likewise. 2005-10-04 Thien-Thi Nguyen * db-rep.el (databases-made): Delete var. (edb): Init symbol property `:databases-made'. (edb--v1-monolithic-mess): Use new prop for `print-name' init form. 2005-10-04 Thien-Thi Nguyen * database.el (db-warning): Move concat to macro-expansion time. 2005-10-04 Thien-Thi Nguyen * db-rep.el (db-lmap): Fix bug introduced in last change: Rename first arg to avoid dynamic binding conflict w/ `maprecords'. 2005-10-04 Thien-Thi Nguyen * db-file-io.el (db-write-1): Call `buffer-disable-undo' with no args. * db-util.el (db-unused-char-in-string, db-best-fit-message): Likewise. * db-format.el (db-next-field-internal, db-change-format): Likewise. (db-previous-field-internal, db-display-record): Likewise. 2005-10-03 Thien-Thi Nguyen * db-rep.el (db-lmap): Document application order. (maprecords): Likewise. Also, rename first arg. * edb.texi (maprecords): Sync doc w/ docstring. 2005-09-30 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Move parens-removal into 0.6 to 0.7 edits. 2005-09-30 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Dynamically bind `emacs-lisp-mode-hook' to nil. 2005-09-30 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Remove parens around record data, if necessary. (db-read-database-file-helper): Convert `read' to iteration. (db-write-1): No longer output parens around record data. 2005-05-28 Thien-Thi Nguyen * db-rep.el (link-set-record): Delete defsubst. (db-new-link): Incorporate `link-set-record'. * db-convert.el (db-convert): Incorporate `link-set-record'. 2005-05-28 Thien-Thi Nguyen * db-rep.el (edb--v1-link): Remove `summary' slot. (link-set-record): No longer set `summary' slot. * db-nosetf.el (link-set-summary): Delete. * db-summary.el (edb--summary-internals): New deflocalvar. (edb--S, edb--S!): New funcs. (dbs-no-of-records, dbs-point, dbs-recompute-p): Delete deflocalvars. (db-summary): Init `edb--summary-internals' and its :summaries. (database-summary-mode): Init internal :nrecords property. (dbs-insert-link-summary): Consult :summaries property. (dbf-fill-summary-buffer): Consult/update :summaries property. Update :nrecords and :recompute-p properties. (dbf-update-summary-item): Consult/update :summaries property. (dbs-in-synch-p): Consult :nrecords property. (dbf-set-summary-out-of-date-p): Update :recompute-p property. (dbs-goto-nth-summary): Update :point property. (dbs-move-to-proper-record): Consult/update :point property. (dbs-delete-record): Update :nrecords property. * db-interfa.el (dbf-finished-sorting): Update :nrecords property. * db-format.el (db-jump-to-point): Consult :point property. (dbf-process-current-record-maybe): No longer set `summary' slot. * edb.texi (The link structure): Remove doc for slot `summary'. 2005-04-11 Thien-Thi Nguyen * db-format.el (dbf-after-display-record-hook): Delete deflocalvar. (db-display-record-redo-inter-field-text-function): Update docstring. (db-display-record): No longer run hook `dbf-after-display-record-hook'. 2005-04-11 Thien-Thi Nguyen * db-format.el (dbf-point-min): Delete defsubst. (db-view-mode): Use `point-min'. (db-next-field-internal): Likewise. (db-first-field-internal): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. (db-display-record): Likewise. 2005-04-11 Thien-Thi Nguyen * db-format.el (edb--v1-ds): Rename structure from `displayspec'. Add options :constructor, :conc-name and :copier. Put associated `kwidx' property on symbol `edb--v1-ds'. (db-dspec<-dtype): Use `edb--copy-v1-ds'. (db-dspec<-type/opts): Use `edb--make-v1-ds'. * db-types.el (define-displaytype-from-displayspec): Use `edb--v1-ds-p', `edb--make-v1-ds' and `edb--copy-v1-ds'. 2005-04-11 Thien-Thi Nguyen * db-rep.el (edb--v1-rs): Rename structure from `recordfieldspec'. Add options :constructor, :conc-name and :copier. Put associated `kwidx' property on symbol `edb--v1-rs'. (database-recordfieldspec): Use `edb--v1-rs-p'. (database-set-recordfieldspec): Likewise. (database-recordfieldspec-type): Likewise. * db-types.el (define-recordfieldtype-from-recordfieldspec): Use `edb--v1-rs-p', `edb--copy-v1-rs' and `edb--make-v1-rs'. * db-tagged.el (db-tagged-setup): Use `edb--copy-v1-rs'. * db-rdb.el (db-rdb-setup): Likewise. 2005-04-11 Thien-Thi Nguyen * skram/make-hacksup.el: Handle defstruct option `:conc-name'. 2005-04-11 Thien-Thi Nguyen * db-rep.el (edb--v1-link): Rename structure from `link'. Add options :type and :conc-name. 2005-04-11 Thien-Thi Nguyen * db-rep.el (edb--v1-sepinfo): Rename structure from `sepinfo'. Add options :type, :constructor and :conc-name. (edb--v1-monolithic-mess): Use `edb--make-v1-sepinfo' for constructors. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, also remove structure tags for slots `record-sepinfo' and `field-sepinfo'. * edb.texi (The sepinfo structure): Downplay "sepinfo" internal name. 2005-04-11 Thien-Thi Nguyen * db-util.el (db-skip-regexp-forward): No longer take arg MATCH-NO. (db-skip-regexp-backward): Likewise. 2005-04-11 Thien-Thi Nguyen * database.el (edb--databases): Take additional args MKEY and MVAL. Do various hash table operations depending on their values. * db-rep.el (edb--field-nm2no): Update call to `edb--databases'. * db-file-io.el (db-read-database-file): Likewise. (db-read-database-internal-file-layout): Likewise. (db-read-database-file-helper): Likewise. (db-write-1): Likewise. * db-format.el (db-setup-data-display-buffer): Likewise. * db-interfa.el (db-toggle-internal-file-layout): Likewise. 2005-04-11 Thien-Thi Nguyen * db-rep.el (db-fname<-fno): Make second arg non-optional. 2005-04-10 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Remove slot `internal-file-layout-p'. * db-file-io.el (db-read-database-internal-file-layout): Set :togp property in global hash, not `internal-file-layout-p' slot. For 0.6 to 0.7 edits, also remove slot for `internal-file-layout-p'. (db-read-database-file): Check :togp, not `internal-file-layout-p' slot. (db-read-database-file-helper): Likewise. (db-write-1): Likewise. * db-format.el (db-setup-data-display-buffer): Likewise. * db-interfa.el (db-toggle-internal-file-layout): Toggle :togp. * db-nosetf.el (database-set-internal-file-layout-p): Delete. * edb.texi: Throughout, no longer mention `internal-file-layout-p'. (The database structure): Move `db-toggle-internal-file-layout' from here... (Internal file layout): ...to here. 2005-04-10 Thien-Thi Nguyen * db-rep.el (edb--v1-monolithic-mess): Rename struct from `database'. Add options :type, :constructor, :conc-name and :copier. * db-two-dbs.el (db-merge): Use `edb--copy-v1-monolithic-mess'. * db-file-io.el (db-read-database-file): Likewise. (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, also remove structure tag. * edb.texi (The database structure): No longer mention structure name. 2005-04-10 Thien-Thi Nguyen * db-file-io.el (db-buffer): Wrap `eval-when-compile' around defvar. 2005-04-10 Thien-Thi Nguyen * db-file-io.el (database): Wrap `eval-when-compile' around defvar. * db-tagged.el (database): Likewise. * db-rdb.el (database): Likewise. 2005-04-10 Thien-Thi Nguyen * db-format.el (db-setup-data-display-buffer): Dynamically bind var `database' around the call to `db-really-hack-local-variables'. 2005-04-10 Thien-Thi Nguyen * db-convert.el (db-convert): Rename arg DATABASE to DB; nfc. (db-canonicalize-creation-method): Likewise. * db-two-dbs.el (db-merge-records): Likewise. * db-sort.el (database-sort): Likewise. (db-convert-ordering-fields): Likewise. (db-make-ordering-fields-canonical): Likewise. (database-sorted-p): Likewise. (database-ordered-p): Likewise. (database-sort-interface): Likewise. * db-summary.el (dbf-make-summary-maker): Likewise. (db-format->lines/sforms): Likewise. * db-format.el (db-dspec<-string): Likewise. (db-setup-data-display-buffer): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. * db-interfa.el (database-clean-data-display-buffers): Likewise. (db-output-record-to-db): Likewise. * db-file-io.el (db-choose-format-file): Likewise. (db-read-database-file-helper): Likewise. (database-set-links-from-list): Likewise. (db-read-file-custom): Likewise. (db-read-file-delimited): Likewise. (db-read-file-delimstr): Likewise. (db-read-file-delimrx): Likewise. (database-delete-pre-and-post): Likewise. (db-write-1): Likewise. (db-write-intdelim): Likewise. (database-io-setup): Likewise. (database-check-sepinfo): Likewise. (database-substitute-for-read): Likewise. (database-perform-substitutions): Likewise. (database-substitute-for-write): Likewise. (database-generate-delimiter): Likewise. * db-rep.el (database-make-local): Likewise. (database-set-local): Likewise. (database-get-local): Likewise. (database-local-p): Likewise. (database-set-fieldnames-to-list): Likewise. (database-full-fieldsep-string): Likewise. (database-full-recordsep-string): Likewise. (database-recordfieldspec): Likewise. (database-set-recordfieldspec): Likewise. (database-recordfieldspec-type): Likewise. (db-check-constraint): Likewise. (record-set-field): Likewise. (db-next-link-and-index): Likewise. (database-add-record): Likewise. (db-lmap): Likewise. (maprecords): Likewise. 2005-04-09 Thien-Thi Nguyen * db-rep.el (database): Remove slot `fieldname-alist'. (database-set-fieldnames-to-list): No longer set slot `fieldname-alist'. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, also remove slot `fieldname-alist'. * db-format.el (db-setup-data-display-buffer): Use `number-sequence' to compute slot `field-priorities'. (dbf-set-summary-format): Call `dbf-make-summary-maker' unconditionally. * db-nosetf.el (database-set-fieldname-alist): Delete. * edb.texi (The database structure): Remove doc for slot `fieldname-alist'. 2005-04-08 Thien-Thi Nguyen * db-rep.el (edb--field-nm2no): New func. (fieldname->fieldnumber): Delete. (database-recordfieldspec): Use `edb--field-nm2no'. (database-set-recordfieldspec): Likewise. (record-field): Likewise. (record-set-field): Likewise. * db-format.el (dbf-fieldname->displayspecno): Likewise. (dbf-set-change-function): Likewise. (db-dspec<-string): Likewise. * db-tagged.el (db-tagged-setup): Likewise. (db-tagged-wrfr): Likewise. * db-sort.el (db-convert-ordering-fields): Likewise. (db-make-ordering-fields-canonical): Likewise. * db-rdb.el (db-rdb-setup): Likewise. (db-rdb-list-wrfr): Likewise. * db-convert.el (db-canonicalize-creation-method): Likewise. * edb.texi (The database structure): Remove refs to `fieldname->fieldnumber'. (Accessing record fields): Remove doc for `fieldname->fieldnumber'. 2005-04-08 Thien-Thi Nguyen * database.el (edb--databases): Take optional arg SPECIFICALLY. If specified, return, creating if necessary, its metainfo hash. * db-file-io.el (db-read-database-file-helper): Use `edb--databases' to register instead of "manual" puthash. * db-two-dbs.el (db-merge): Likewise. 2005-04-08 Thien-Thi Nguyen * database.el (db-databases): Init as hash table. (edb--databases): New func. * db-file-io.el (db-read-database-file-helper): Associate new database with a small hash table in `db-databases'. * db-interfa.el (db-kill-buffers): No longer update `db-databases'. (database-clean-data-display-buffers): Likewise. (db-save-some-databases): Use `edb--databases'. (db-find-read-in-database): Likewise. (db-output-record-to-db): Likewise. * db-two-dbs.el (db-merge): Use `edb--databases'. Also, associate new database with a small hash table in `db-databases'. * edb.texi (Global variables): Update doc for `db-databases'. 2005-04-08 Thien-Thi Nguyen * db-rep.el (database): Remove slot `file-local-variables'. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, also remove slot `file-local-variables'. (db-write-1): No longer output slot `file-local-variables'. * db-nosetf.el (database-set-file-local-variables): Delete. * edb.texi (The database structure): Remove doc for slot `file-local-variables'. 2005-04-08 Thien-Thi Nguyen * db-rep.el (database): Remove slot `alternative-sepinfo'. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, also remove slot `alternative-sepinfo'. (database-io-setup): No longer check slot `alternative-sepinfo'. * db-nosetf.el (database-set-alternative-sepinfo): Delete. * edb.texi (The database structure): Remove doc for slot `alternative-sepinfo'. 2005-04-08 Thien-Thi Nguyen * db-rep.el (database): Remove slot `no-of-fields'. (database-set-fieldnames-to-list): No longer set `no-of-fields' slot. (make-record): Use length of `fieldnames' value. * db-file-io.el (db-read-database-internal-file-layout): For 0.6 to 0.7 edits, also remove slot `no-of-fields'. (db-read-file-delimited): Use length of `fieldnames' value. (db-read-file-delimstr): Likewise. (db-read-file-delimrx): Likewise. (database-stored->actual): Likewise. (db-write-intdelim): Likewise. * db-two-dbs.el (db-merge-records): Likewise. (database-compare-hack): Likewise. * db-sort.el (db-make-ordering-fields-canonical): Likewise. * db-interfa.el (db-add-record): Likewise. * db-format.el (db-setup-data-display-buffer): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. * db-convert.el (db-canonicalize-creation-method): Likewise. * db-nosetf.el (database-set-no-of-fields): Delete. * edb.texi (The database structure): Remove doc for slot `no-of-fields'. 2005-04-08 Thien-Thi Nguyen * db-rep.el (db-lmap-link): Delete var. (db-lmap-index): Update docstring. (db-lmap-break): Delete macro. (db-lmap): Update docstring. Also, munge names of locals. (db-lmap-macro): Delete macro. (maprecords-break): Delete fset. * edb.texi (Mapping over the database): Remove doc for `maprecords-break'. 2005-04-08 Thien-Thi Nguyen * db-summary.el (dbf-fill-summary-buffer): Use `db-lmap'. (dbf-update-summary-marks): Likewise. (dbs-move-to-proper-record): Likewise. * db-sort.el (database-ordered-p): Use `db-lmap'. (database-sorted-p): Use `db-lmap', `catch' and `throw'. * db-convert.el (db-convert): Use `db-lmap'. * db-interfa.el (dbf-finished-sorting): Use `db-lmap', `catch' and `throw'. (db-search-field): Use `db-lmap'. (db-hide-unmarked-records): Likewise. (db-mark-unhidden-records): Likewise. (db-unhide-all): Likewise. (db-unmark-all): Likewise. (db-report): Likewise. 2005-04-08 Thien-Thi Nguyen * db-rep.el (database): Remove slot `hide-functions'. * db-file-io.el (db-read-database-internal-file-layout): Use `delete-char'. Also, add fixups to go from format 0.6 to 0.7. (db-write-1): Write "format 0.7". * edb.texi (The database structure): Remove doc for `hide-functions'. * db-nosetf.el (database-set-hide-functions): Delete. 2005-04-07 Thien-Thi Nguyen * db-format.el (db-jump-to-point): Remove `interactive' spec. (db-emergency-restore-format): Likewise. * db-file-io.el (db-read-database-file): Likewise. 2005-01-24 Thien-Thi Nguyen * configure.ac (VERSION): Bump to "1.25" for release. 2005-01-24 Thien-Thi Nguyen * edb.texi (Function and variable naming conventions): Mention "edb-t-GROUP:" prefix, and define "type group". (File naming conventions): Mention "edb-t-GROUP.el". 2005-01-24 Thien-Thi Nguyen * db-rep.el (recordfieldspec-sort-function): Delete defalias. (recordfieldspec-order-function): Likewise. 2005-01-24 Thien-Thi Nguyen * db-file-io.el (db-rfspec<-rftype): Rename from `recordfieldtype->recordfieldspec'. * db-types.el (define-recordfieldtype-from-recordfieldspec): Use `db-rfspec<-rftype'. * db-rep.el (database-recordfieldspec): Likewise. (database-set-recordfieldspec): Likewise. * edb.texi (The database structure): For `database-recordfieldspec', no longer mention function name used for dereferencying type name. (Accessing record fields): Add scadenza for "access to records via fieldnumber". 2005-01-24 Thien-Thi Nguyen * db-rep.el (copy-record): Delete unused defsubst. 2005-01-24 Thien-Thi Nguyen * db-interfa.el (db-copy-record): Use `copy-sequence'. 2005-01-24 Thien-Thi Nguyen * db-rep.el (db-copy-r2r): Rename from `copy-record-to-record'. * db-format.el (dbf-this-record): Use `db-copy-r2r' in docstring. (dbf-set-this-record-modified-p): Use `db-copy-r2r'. (dbf-process-current-record-maybe): Likewise. 2005-01-24 Thien-Thi Nguyen * db-rep.el (maprecords-macro): Delete unused macro. 2005-01-24 Thien-Thi Nguyen * db-file-io.el (database-stored->actual): Use `maprecords'. 2005-01-24 Thien-Thi Nguyen * edb.texi (Mapping over the database): Add scadenza for `maprecords-break'. 2005-01-24 Thien-Thi Nguyen * edb.texi (Mapping over the database): Remove references to `maprecords-macro'. * db-rep.el (maprecords): No longer mention `maprecords-macro' in docstring. 2005-01-24 Thien-Thi Nguyen * db-format.el (db-dspec<-string): Rename from `make-displayspec-from-string-internal'. (db-setup-ddb-parse-displayspecs): Use `db-dspec<-string'. * db-summary.el (db-format->lines/sforms): Likewise. 2005-01-24 Thien-Thi Nguyen * db-format.el (make-displayspec-from-string): Delete unused func. 2005-01-24 Thien-Thi Nguyen * db-format.el (db-dspec<-type/opts): Rename from `make-displayspec-from-type-and-options'. (make-displayspec-from-string-internal): Use `db-dspec<-type/opts'. * db-types.el (define-displaytype-from-optstring): Likewise. (define-enum-type): Likewise. 2005-01-24 Thien-Thi Nguyen * db-format.el (db-dspec<-dtype): Rename from `displaytype->displayspec'. (make-displayspec-from-type-and-options): Use `db-dspec<-dtype'. * db-types.el (define-displaytype-from-displayspec): Likewise. 2005-01-24 Thien-Thi Nguyen * db-rep.el (db-fname<-fno): Rename from `fieldnumber->fieldname'. (db-check-constraint): Use `db-fname<-fno'. * db-two-dbs.el (db-merge-records): Likewise. (database-compare-hack): Likewise. * db-sort.el (db-convert-ordering-fields): Likewise. (db-make-ordering-fields-canonical): Likewise. (dbsi-format): Likewise. * db-interfa.el (db-field-help): Likewise. (db-field-query-replace): Likewise. * db-format.el (dbf-this-field-name): Likewise. (db-jump-to-point): Likewise. 2005-01-24 Thien-Thi Nguyen * skram/GNUmakefile (clean): Also delete sk4. 2005-01-24 Thien-Thi Nguyen * edb.texi (Reporting bugs): Delete node/section and references to it. 2005-01-22 Thien-Thi Nguyen * GNUmakefile.in (edb.info): Specify output file to makeinfo(1). 2005-01-19 Thien-Thi Nguyen * edb.texi (The database structure): No longer mention `fieldnumber->fieldname'. (Accessing record fields): Bump scadenza of `fieldname->fieldnumber' to EDB 1.26. 2005-01-19 Thien-Thi Nguyen * db-sort.el (db-convert-ordering-fields): If first spec element is a symbol, take it as a field name and convert it to a field number internally. 2005-01-19 Thien-Thi Nguyen * db-rep.el (database-recordfieldspec): If second arg is a symbol, take it as a field name and convert it to a field number internally. (database-set-recordfieldspec): Likewise. * edb.texi (The database structure): Update docs for `database-recordfieldspec' and `database-set-recordfieldspec'. 2005-01-19 Thien-Thi Nguyen * db-summary.el (database-summary-mode-map): Bind `t' to `toggle-truncate-lines'. 2005-01-19 Thien-Thi Nguyen * edb.texi: Add back "\input texinfo" removed 2004-09-17. Suggested by Erich Waelde. 2005-01-19 Thien-Thi Nguyen * GNUmakefile.in (distfiles): Remove Makefile.in. Add GNUmakefile.in. 2005-01-19 Thien-Thi Nguyen * GNUmakefile.in (VPATH): New var. (all): Use $(srcdir). ($(ELC-FILES):): Likewise. Also, remove superfluous reference to database.el. 2005-01-19 Thien-Thi Nguyen * GNUmakefile.in: New file. * configure.ac (AC_CONFIG_FILES): Remove Makefile. Add GNUmakefile. * Makefile.in: Delete file. 2005-01-19 Thien-Thi Nguyen * Makefile.in (TEXI2DVI): New var. (.tex.dvi): New suffix-rule target. (.texi.dvi): Likewise. 2005-01-19 Thien-Thi Nguyen * edb-t-timedate1.el: Doc fixes and clarifications; nfc. 2005-01-19 Thien-Thi Nguyen * edb.texi: Use "setf construction" to document structure mutation. Also, add examples. (Local variables): Delete node/section and children. 2005-01-18 Thien-Thi Nguyen * configure.ac: Add AC_CONFIG_FILES entry for script "test/ebatch". 2005-01-18 Thien-Thi Nguyen * skram/make-skram.el (make-skram): For GNU Emacs 21.2: use one-arg `info'. Also, ensure that skram.data is written to default directory. 2005-01-18 Thien-Thi Nguyen * db-util.el (with-selected-window): Define macro if not builtin. 2005-01-18 Thien-Thi Nguyen * edb.texi (Creating a new database): Use `iso-safe' in example. 2005-01-18 Thien-Thi Nguyen * db-util.el (db-locate-readable-file-prefer-cwd): New func. * db-format.el (db-setup-data-display-buffer): Use `db-locate-readable-file-prefer-cwd'. * db-file-io.el (db-file->format-file): Likewise. (db-locate-format-file): Likewise. Reported by Erich Waelde. 2005-01-18 Thien-Thi Nguyen * db-util.el (db-same-file-p): Call `file-chase-links' w/ one arg. * db-rep.el (db-default-field-type): Defvar when compiling. (database-set-fieldnames-to-list): Do not use value of `db-default-field-type' if it is nil. * db-file-io.el (edb-data-coding): Defvar when compiling. (db-read-database-file): Do not use value of `edb-data-coding' if it is nil. 2005-01-18 Thien-Thi Nguyen * skram/GNUmakefile (all): Also depend on sk4. 2005-01-18 Thien-Thi Nguyen * db-types.el (db-string-lessp-ci): Rename from name w/o "db-". (db-string-order-ci): Likewise. (db-make-regexp-pattern): Likewise. (db-regexp-pattern-regexp): Likewise. (db-make-string-pattern): Likewise. (db-string-pattern-regexp): Likewise. (db-string-pattern-string): Likewise. (db-string-match-function): Likewise. (db-string-match-display->actual): Likewise. (db-string-match-actual->display): Likewise. (db-string-or-nil->string): Likewise. (db-string-or-nil-lessp-ci): Likewise. (db-string-or-nil-order-ci): Likewise. (db-string-or-nil-match-function): Likewise. (db-string->nil-or-string): Likewise. * db-oldnames.el (string-lessp-ci): New defalias. (string-order-ci): Likewise. (make-regexp-pattern): Likewise. (regexp-pattern-regexp): Likewise. (make-string-pattern): Likewise. (string-pattern-regexp): Likewise. (string-pattern-string): Likewise. (string-match-function): Likewise. (string-match-display->actual): Likewise. (string-match-actual->display): Likewise. (string-or-nil->string): Likewise. (string-or-nil-lessp-ci): Likewise. (string-or-nil-order-ci): Likewise. (string-or-nil-match-function): Likewise. (string->nil-or-string): Likewise. 2005-01-18 Thien-Thi Nguyen * db-util.el (db-string->integer-default): Delete func. (db-string->number-default): Delete alias. (db-string->integer-or-nil): Incorporate `db-string->integer-default'. 2005-01-17 Thien-Thi Nguyen * db-rep.el (db-rs-sortfunc): Fix bug: Maintain arg order and invert the result so as to properly handle the case: (eq value1 value2). Suggested by Erich Waelde and Matt Swift. 2005-01-17 Thien-Thi Nguyen * db-convert.el (db-canonicalize-creation-method): Fix bug: Return list instead of cons. Suggested by Erich Waelde and Matt Swift. 2005-01-17 Thien-Thi Nguyen * db-types.el (define-alternative-multi-char-displaytype): Delete fset. * db-oldnames.el (define-alternative-multi-char-displaytype): New defalias. 2005-01-16 Thien-Thi Nguyen * database.el (edb-essential-file-names): Remove "db-nosetf". * Makefile.in (ELC-FILES): Remove db-nosetf.elc. (install): Clear out $(edb-elc-dir) before install. 2005-01-16 Thien-Thi Nguyen * db-format.el (db-optspec-list): No longer refer to "displayspec-set-FOO" functions. Use `setf' forms instead. 2005-01-16 Thien-Thi Nguyen * skram/GNUmakefile (sk4): New target. 2005-01-16 Thien-Thi Nguyen * edb.texi (Read hooks): Rename from "Load and read hooks". Update refs. Remove @defvar for `db-load-hooks'. 2005-01-16 Thien-Thi Nguyen * edb.texi (Accessing record fields): Remove @defun entries for `fieldnumber->fieldname', `record-field-from-index' and `record-set-field-from-index'. 2005-01-16 Thien-Thi Nguyen * edb.texi (Tagged file layout): No longer mention `database-set-local'. Convert @defvar entries to items in a @table, and var names to their associated keywords. 2005-01-15 Thien-Thi Nguyen * edb-t-human-names.el: Add `provide' form. * edb-t-places-usuk.el: Likewise. 2005-01-15 Thien-Thi Nguyen * db-file-io.el (db-write-1): For internal layout format, do not include `coding' in first line if it starts with "undecided-". 2005-01-15 Thien-Thi Nguyen * edb.texi (Plans for EDB): Remove node/section and references. 2005-01-15 Thien-Thi Nguyen * edb-t-timedate1.el: New file. * db-time.el: Delete file. * Makefile.in (EL-FILES): Remove db-time.el. Add edb-t-timedate1.el. (ELC-FILES): Remove db-time.elc. Add edb-t-timedate1.elc. * db-oldnames.el: Require `edb-t-timedate1'. (make-date): New defalias. (date-year): Likewise. (date-month): Likewise. (date-day): Likewise. (make-empty-date): Likewise. (date-year-long): Likewise. (date->day-of-year): Likewise. (date->absolute-days): Likewise. (date->weekday-index): Likewise. (date->weekday-name): Likewise. (date-order-absolute): Likewise. (parse-date-string): Likewise. (parse-date-string-or-nil): Likewise. (parse-date-default-function): Likewise. (format-date): Likewise. (simple-format-date): Likewise. (simple-format-date-or-nil): Likewise. (format-date-mmddyy): Likewise. (format-date-ddmmyy): Likewise. (format-date-yymmdd): Likewise. (format-date-ddmmmyy): Likewise. (format-date-yyyymmdd): Likewise. (format-date-full): Likewise. (format-date-unix): Likewise. (format-date-all): Likewise. (format-date-dec): Likewise. (format-date-europe): Likewise. (date-match-function): Likewise. (date-merge): Likewise. (date->storage-string-mmddyyyy): Likewise. (storage-string-mmddyyyy->date): Likewise. (date->storage-string-lisp): Likewise. (storage-string-lisp->date): Likewise. (date-stored->actual): Likewise. (make-time): Likewise. (time-hours): Likewise. (time-mins): Likewise. (time-secs): Likewise. (make-empty-time): Likewise. (empty-time-p): Likewise. (time-default-constraint): Likewise. (parse-time-string): Likewise. (parse-time-default-function): Likewise. (format-time-24): Likewise. (format-time-12): Likewise. (format-time-12-hhmm): Likewise. (format-time-24-hhmm): Likewise. (time-order): Likewise. (time-match-function): Likewise. (time->storage-string): Likewise. (storage-string->time): Likewise. (time-merge): Likewise. (date->storage-string): Likewise. (storage-string->date): Likewise. (format-time-hhmm): Likewise. * database.el (edb-essential-file-names): Remove "db-time". (edb-byte-compile-all): Byte compile "edb-t-timedate1". * edb.texi: Use "edb-t-timedate1:" prefix. 2005-01-15 Thien-Thi Nguyen * db-interfa.el (database-view-mode-map): Bind `t' to `toggle-truncate-lines'. 2005-01-14 Thien-Thi Nguyen * db-file-io.el: Make `db-message' output follow Emacs conventions (mostly). * db-format.el: Likewise. * db-interfa.el: Likewise. * db-sort.el: Likewise. * db-summary.el: Likewise. * db-tagged.el: Likewise. * db-two-dbs.el: Likewise. 2005-01-14 Thien-Thi Nguyen * Makefile.in (ELC-FILES): Add edb-t-human-names.elc and edb-t-places-usuk.elc. 2005-01-14 Thien-Thi Nguyen * database.el (db-inform-interval): Increase value to 100. 2005-01-14 Thien-Thi Nguyen * db-file-io.el (database-substitute-for-read): Use `string-to-list' for some `db-message' string args. 2005-01-14 Thien-Thi Nguyen * database.el (edb-byte-compile-all): Also byte-compile "edb-t-human-names" and "edb-t-places-usuk". 2005-01-14 Thien-Thi Nguyen * database.el: Remove autoload/defsubst forms for db-summary.el. (edb-byte-compile-all): Remove "db-summary" from explicit list. 2005-01-14 Thien-Thi Nguyen * skram/make-skram.el (make-skram): Avoid false positives in "grep -l" emulation by checking char before the match string. 2005-01-14 Thien-Thi Nguyen * edb-t-human-names.el: New file. * Makefile.in (EL-FILES): Add edb-t-human-names.el. * db-oldnames.el: Require `edb-t-human-names'. (order-last-names): New defalias. (canonicalize-name): Likewise. (same-first-name-p): Likewise. (order-first-names): Likewise. (nicknamep): Likewise. (standardize-name): Likewise. (name->name-jr): Likewise. (name->first-last-jr): Likewise. * db-types.el (order-last-names): Delete func. (canonicalize-name): Likewise. (nicknames): Delete var. (same-first-name-p): Delete func. (order-first-names): Likewise. (nicknamep): Likewise. (standardize-name): Likewise. (jr-assoc-list): Delete var. (name->name-jr): Delete func. (name->first-last-jr): Likewise. 2005-01-14 Thien-Thi Nguyen * edb-t-places-usuk.el: New file. * Makefile.in (EL-FILES): Add edb-t-places-usuk.el. * db-oldnames.el: Provide `db-oldnames'. Require `edb-t-places-usuk'. (postal-code-p): New defalias. (statep): Likewise. (full-state-name): Likewise. (abbreviate-state): Likewise. * db-types.el (UK-postal-code-regexp): Delete var. (zip-code-regexp): Likewise. (postal-code-regexp): Likewise. (postal-code-p): Delete func. (state-alist): Delete var. (statep): Delete func. (full-state-name): Likewise. (abbreviate-state): Likewise. 2005-01-14 Thien-Thi Nguyen * edb.texi: Use `setf' forms in examples. 2005-01-14 Thien-Thi Nguyen * edb.texi (Execution of format file eval expressions): No longer mention `database-set-fieldnames' explicitly. 2005-01-14 Thien-Thi Nguyen * database.el (edb-essential-file-names): Add "db-summary". 2005-01-13 Thien-Thi Nguyen * edb.texi (Creating a new database): Document `edb-data-coding'. Update last example to use it. Add two @cindex entries. 2005-01-13 Thien-Thi Nguyen * db-oldnames.el: New file. * Makefile.in (EL-FILES): Add db-oldnames.el. 2005-01-13 Thien-Thi Nguyen * db-rep.el (db-make-n-line-sep-function): Rename from `make-n-line-sep-function'. * edb.texi (Sepinfo examples): Use `db-make-n-line-sep-function'. 2005-01-13 Thien-Thi Nguyen * edb.texi (Introduction): Add menu item "Plans for EDB". (Plans for EDB): New node/section. 2005-01-13 Thien-Thi Nguyen * db-file-io.el (db-read-database-file): Use two `db-in-buffer' blocks since the re-coding hack may obsolete the original buffer. 2005-01-13 Thien-Thi Nguyen * skram/skram.edb: New file. * Makefile.in (distfiles): Add skram/skram.edb. 2005-01-13 Thien-Thi Nguyen * edb.texi: Bump some 1.25 scadenzas to 1.26. 2005-01-13 Thien-Thi Nguyen * db-file-io.el (db-read-database-file): Reread data file if coding system is different than the default. (db-read-database-internal-file-layout): Set the `internal-file-layout-p' slot in the returned structure. (db-write-1): Take additional arg `coding'. Update callers. Include `coding' in output as the first-line magic variable. * db-interfa.el (db-write-database-file): Pass data display buffer's `buffer-file-coding-system' value to `db-write-1'. 2005-01-12 Thien-Thi Nguyen * db-rep.el (database-set-modified-p): Fix typo. Reported by NAKAMURA Toshikazu. 2005-01-12 Thien-Thi Nguyen * edb.texi (Reporting bugs): No longer mention defunct var `db-prepare-to-debug'. Instead, suggest setting var `debug-on-error'. 2005-01-12 Thien-Thi Nguyen * edb.texi (Debugging EDB): Remove subsubsections on enabling debugging messages and printing circular structures. 2005-01-10 Thien-Thi Nguyen * edb.texi: Remove/rework some @scandeza items. 2004-10-25 Thien-Thi Nguyen * db-summary.el (db-summary): Doc fix; nfc. * db-interfa.el (dbc-set-hide-p): Likewise. (db-hide-unmarked-records): Likewise. 2004-10-13 Thien-Thi Nguyen * configure.ac (VERSION): Bump to "1.24" for release. 2004-10-13 Thien-Thi Nguyen * Makefile.in (distfiles): Add skram/make-skram.el and skram/make-hacksup.el. 2004-10-13 Thien-Thi Nguyen * BUGS: New file. * Makefile.in (distfiles): Add BUGS. 2004-10-13 Thien-Thi Nguyen * database.el (edb-byte-compile-all): Rename from `byte-compile-database-all'. * Makefile.in ($(ELC-FILES)): Use `edb-byte-compile-all'. 2004-10-12 Thien-Thi Nguyen * db-rep.el (db-lmap-link): Rename from `maplinks-link'. (db-lmap-index): Rename from `maplinks-index'. (db-lmap): Rename from `maplinks'. (db-lmap-macro): Rename from `maplinks-macro'. (db-lmap-break): Rename from `maplinks-break'. (maprecords): Update docstring; nfc. (maprecords-macro): Likewise. * db-summary.el (dbf-fill-summary-buffer): Use db-lmap-* names. (dbf-update-summary-marks): Likewise. (dbs-move-to-proper-record): Likewise. * db-sort.el (database-sort): Likewise. (database-sorted-p): Likewise. (database-ordered-p): Likewise. * db-interfa.el (dbf-finished-sorting): Likewise. (db-search-field): Likewise. (db-hide-unmarked-records): Likewise. (db-mark-unhidden-records): Likewise. (db-unhide-all): Likewise. (db-unmark-all): Likewise. (db-report): Likewise. * db-convert.el (db-convert): Likewise. 2004-10-12 Thien-Thi Nguyen * db-rep.el (mapfields-field): Delete var. (mapfields-index): Likewise. (mapfields): Delete macro. (mapfields-macro): Likewise. * edb.texi (Mapping over record fields): Delete node/subsection. 2004-10-12 Thien-Thi Nguyen * edb.texi (Mapping over the database): Remove docs for `maplinks', `maplinks-macro' and `maplinks-break'. 2004-10-12 Thien-Thi Nguyen * db-interfa.el (db-delete-record-modifies-database-p): Delete var. (db-delete-record): No longer use var. * edb.texi (Adding and removing records): Remove @defvar for `db-delete-record-modifies-database-p'. 2004-10-12 Thien-Thi Nguyen * db-format.el (dbf-fieldabbrevs): Delete var. (make-displayspec-from-string-internal): No longer use `dbf-fieldabbrevs'. * edb.texi (Display specification abbreviations): Delete node/section. Remove menu refs. 2004-10-12 Thien-Thi Nguyen * edb.texi: Add scadenza for `recordfieldspec', `sepinfo' `database' and `link' structures. Also, rewrite get/set intro to say "functions whose names take the form". 2004-10-11 Thien-Thi Nguyen * skram/skram.fmt: Set summary format in Local Variables section. 2004-10-11 Thien-Thi Nguyen * edb.texi (Database Summary mode): Fix omission bug: Include argument for `dbf-set-summary-format' @defun. 2004-10-11 Thien-Thi Nguyen * database.el (edb-required-file-names): Delete var. (edb-autoloaded-file-names): Likewise. (edb-file-names): Likewise. (edb-source-file-names): Likewise. (byte-compile-database-all): Incorporate values of deleted vars. 2004-10-11 Thien-Thi Nguyen * database.el (edb-directory): Delete var. (byte-compile-database-all): No longer take arg `dir'. * Makefile.in ($(ELC-FILES)): Prefix `load-path' in Emacs command. 2004-10-10 Thien-Thi Nguyen * database.el (byte-compile-database): Delete func. (byte-compile-database-all): Incorporate `byte-compile-database'. No longer autoload. No longer support interactive calling. Consult `default-directory' instead of `edb-directory' or querying. Touch old .elc files if any compilation happens. 2004-10-10 Thien-Thi Nguyen * database.el (load-database): Delete func. (byte-compile-database): Incorporate `load-database'. 2004-10-10 Thien-Thi Nguyen * edb.texi (Defining new displaytypes): Add scadenza for `define-displaytype-from-optstring'. Also, no longer mention `displayspec' structure slots. 2004-10-10 Thien-Thi Nguyen * edb.texi (Predefined record field types): Add scadenza for `define-type-alias'. 2004-10-10 Thien-Thi Nguyen * db-util.el (db-best-fit-message): Use `with-output-to-temp-buffer' instead of `with-electric-help-maybe'. (with-electric-help-maybe): Delete macro. (use-electric-help-p): Delete var. * database.el (with-electric-help): Delete autoload form. * edb.texi (Global variables): Remove @defvar and associated blurb for `use-electric-help-p'. Likewise for `with-electric-help-maybe' @defmac. 2004-10-10 Thien-Thi Nguyen * db-types.el (db-use-completing-read): Delete var. (define-enum-type): Incorporate `db-use-completing-read' value. 2004-10-08 Thien-Thi Nguyen * database.el: Move "db-lemacs" loading together with other loading. * db-lemacs.el: No longer require `database'. No longer provide `db-lemacs'. Convert multiple checks for `emacs-version' property `edb-running-lemacs' to a single check at the start of the file that can signal error. 2004-10-08 Thien-Thi Nguyen * skram/GNUmakefile (sk2): Avoid vc interaction. (sk3): Likewise. 2004-10-08 Thien-Thi Nguyen * edb.texi (Invoking EDB): No longer mention db-lemacs.el. * database.el: Load "db-lemacs" if running under Lucid Emacs. * db-lemacs.el (db-running-lucid-emacs): Delete var. Replace refs with checks to `emacs-version' property `edb-running-lemacs'. 2004-10-08 Thien-Thi Nguyen * edb.texi (Load and read hooks): Move scadenza for `db-load-hooks' to 1.25. 2004-10-08 Thien-Thi Nguyen * skram/skram.fmt: Merge `eval' forms in Local Variables section; use `setf' instead of TYPE-set-SLOT functions. 2004-10-07 Thien-Thi Nguyen * db-two-dbs.el (db-merge-internal): Delete func. (db-merge): Incorporate `db-merge-internal'. 2004-10-07 Thien-Thi Nguyen * db-two-dbs.el (db-choose-value): Delete func. (db-merge-records): Incorporate `db-choose-value'. 2004-10-07 Thien-Thi Nguyen * db-two-dbs.el (db-read-fieldvalue-from-minibuffer): Delete func. (db-choose-value): Incorporate `db-read-fieldvalue-from-minibuffer'. 2004-10-07 Thien-Thi Nguyen * db-tagged.el (db-tagged-lookup-field): Delete func. (db-tagged-rrfr): Incorporate `db-tagged-lookup-field'. 2004-10-07 Thien-Thi Nguyen * db-util.el (db-buffer-substitute): Delete func. * db-file-io.el (database-perform-substitutions): Incorporate `db-buffer-substitute'. 2004-10-07 Thien-Thi Nguyen * db-util.el (db-operate-on-local-variables): Delete func. * db-format.el (db-setup-ddb-parse-displayspecs): Incorporate `db-operate-on-local-variables'. 2004-10-07 Thien-Thi Nguyen * db-rdb.el (db-rdb-setup-internal): Delete func. (db-rdb-setup): Incorporate `db-rdb-setup-internal'. 2004-10-07 Thien-Thi Nguyen * db-rdb.el (db-rdb-lookup-field): Delete func. (db-rdb-list-rrfr): Incorporate `db-rdb-lookup-field'. 2004-10-07 Thien-Thi Nguyen * db-rdb.el (db-rdb-format-to-type): Delete func. (db-rdb-correlate-field-defs): Incorporate `db-rdb-format-to-type'. 2004-10-07 Thien-Thi Nguyen * db-rdb.el (db-rdb-read-list-field-defs): Delete func. (db-rdb-read-table-field-defs): Likewise. (db-rdb-read-fields): Incorporate deleted funcs. 2004-10-07 Thien-Thi Nguyen * db-rep.el (make-similar-database): Delete func. * db-two-dbs.el (db-merge): Incorporate `make-similar-database'. 2004-10-07 Thien-Thi Nguyen * edb.texi (Per-database variables): Add scadenza for subsection. 2004-10-07 Thien-Thi Nguyen * db-tagged.el (db-tagged-setup): Take rest-arg `attrs'. Use `attrs' to override db-tagged-* values. * edb.texi (Tagged file layout): Update @defun for `db-tagged-setup'. Add scadenza for "setting attributes using `database-set-local'". 2004-10-07 Thien-Thi Nguyen * db-rep.el (database-add-record): Use `db-new-link'. 2004-10-07 Thien-Thi Nguyen * db-tagged.el (db-tagged-setup-internal): Delete func. (db-tagged-setup): Incorporate `db-tagged-setup-internal'. 2004-10-07 Thien-Thi Nguyen * db-types.el (define-displaytype-from-displaysp): Return name. (define-recordfieldtype-from-recordfieldspec): Likewise. * edb.texi (Specifying a record field type): Update @defun for `define-recordfieldtype-from-recordfieldspec'. (Defining new displaytypes): Likewise for `define-displaytype-from-displayspec'. 2004-10-07 Thien-Thi Nguyen * skram/make-skram.el: Use the documented method for disabling vc. 2004-10-06 Thien-Thi Nguyen * db-rep.el (db-join-links): Rename from `link-two'. (database-add-record): Use `db-join-links'. * db-interfa.el (db-delete-record): Use `db-join-links'. * db-file-io.el (database-set-links-from-list): Likewise. (db-reading-noninternal): Likewise. 2004-10-06 Thien-Thi Nguyen * edb.texi (The link structure): Add scadenza for "the link structure". 2004-10-06 Thien-Thi Nguyen * db-rep.el (link): For this defstruct, rename constructor from `old-make-link' to `db-make-link'. (db-new-link): Use `db-make-link'. 2004-10-06 Thien-Thi Nguyen * db-rep.el (db-new-link): Rename from `make-link-from-record'. * db-file-io.el (db-read-database-file-helper): Use `db-new-link'. (db-reading-noninternal): Likewise. 2004-10-06 Thien-Thi Nguyen * db-rep.el (make-link): Delete unused func and associated `make-obsolete' form. 2004-10-06 Thien-Thi Nguyen * db-rep.el (recordfieldspec-sort-function): New alias. (recordfieldspec-order-function): Likewise. * edb.texi (The recordfieldspec structure): Add scadenza for `recordfieldspec-sort-function' and `recordfieldspec-order-function'. 2004-10-06 Thien-Thi Nguyen * db-rep.el (db-rs-sortfunc): Rename from `recordfieldspec-sort-function'. * db-sort.el (dbsi-this-field-only): Use `db-rs-sortfunc'. 2004-10-06 Thien-Thi Nguyen * db-rep.el (db-rs-ordfunc): Rename from `recordfieldspec-order-function'. * db-two-dbs.el (database-compare-hack): Use `db-rs-ordfunc'. * db-sort.el (db-convert-ordering-fields): Likewise. * db-search.el (db-match): Likewise. * db-interfa.el (db-field-query-replace): Likewise. 2004-10-06 Thien-Thi Nguyen * edb.texi (Manipulating records): Add scadenza for `copy-record' and `copy-record-to-record'. 2004-10-06 Thien-Thi Nguyen * db-rep.el (db-check-constraint): Rename from `record-check-constraint'. (record-set-field-from-index): Use `db-check-constraint'. * db-interfa.el (db-field-query-replace): Use `db-check-constraint'. 2004-10-06 Thien-Thi Nguyen * edb.texi (Accessing record fields): Add scadenza for `record-set-field-from-index' and `record-field-from-index'. 2004-10-06 Thien-Thi Nguyen * db-rep.el (dbf-this-record-set-field-and-redisplay): Delete unused func and associated `make-obsolete' form. 2004-10-06 Thien-Thi Nguyen * edb.texi (Mapping over the database): Add scadenza for `maprecords-macro' and `maplinks-macro'. (Mapping over record fields): Add scadenza for `mapfields-macro'. (Sepinfo examples): Add scadenza for `make-n-line-sep-function'. 2004-10-06 Thien-Thi Nguyen * db-rep.el (map-data-display-buffers): Delete func. (database-set-modified-p): Make a defun. Incorporate `map-data-display-buffers'. 2004-10-06 Thien-Thi Nguyen * db-file-io.el (database-stored->actual-internal): Delete func. (database-stored->actual): Incorporate `database-stored->actual-internal'. 2004-10-06 Thien-Thi Nguyen * edb.texi (Specifying a record field type): Rewrite. Also, add scadenza for `recordfieldtype->recordfieldspec'. 2004-10-05 Thien-Thi Nguyen * db-file-io.el (db-set-field-variables): Delete func. * db-format.el (db-setup-data-display-buffer): Incorporate `db-set-field-variables'. 2004-10-05 Thien-Thi Nguyen * db-file-io.el (database-check-all-sepinfos): Delete func. (database-io-setup): Incorporate `database-check-all-sepinfos'. 2004-10-05 Thien-Thi Nguyen * db-format.el (db-display-record): Rename from `display-record'. (db-revert-record): Use `db-display-record'. (db-emergency-restore-format): Likewise. * db-interfa.el (dbf-goto-record-internal): Likewise. (db-field-query-replace): Likewise. * db-two-dbs.el (db-merge-records): Likewise. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (db-kill-buffers): Fix typo. 2004-10-05 Thien-Thi Nguyen * edb.texi (Record display hooks): No longer mention `display-record'. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (db-set-field-help): Delete unused func. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (dbf-kill-summary): Delete func. (db-kill-buffers): Incorporate `dbf-kill-summary'. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (db-bury): Delete func. (db-quit): Incorporate `db-bury'. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (db-this-buffer): Delete unused func. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (db-save-database-no-buffer): Delete func. (database-clean-data-display-buffers): Incorporate `db-save-database-no-buffer'. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (db-auto-edit-mode): Delete var. (db-set-auto-edit-mode): Delete func. (db-toggle-auto-edit-mode): Likewise. 2004-10-05 Thien-Thi Nguyen * db-interfa.el (db-hide-records): Delete unused func. 2004-10-05 Thien-Thi Nguyen * edb.texi (Accessing record fields): Add scadenza for `fieldname->fieldnumber' and `fieldnumber->fieldname'. 2004-10-05 Thien-Thi Nguyen * db-format.el (dbf-install-format-spec): Delete func. (format-spec-format-file): Likewise. (dbf-make-format-file-spec): Likewise. (dbf-install-format-file-spec): Likewise. (db-change-format): Incorporate deleted funcs. 2004-10-05 Thien-Thi Nguyen * db-format.el (dbf-this-field-text-unrect): Delete func. (dbf-process-field-maybe): Incorporate `dbf-this-field-text-unrect'. 2004-10-05 Thien-Thi Nguyen * db-format.el (db-mouse-buffer-switch-moves-point-p): Delete unused var. 2004-10-05 Thien-Thi Nguyen * db-format.el (dbf-check-if-beyond-field): Delete func. (dbf-check-if-before-field): Likewise. (dbf-check-if-outside-field): Incorporate deleted funcs. 2004-10-05 Thien-Thi Nguyen * db-format.el (dbf-in-indentation-p): Delete func. (db-jump-to-point): Incorporate `dbf-in-indentation-p'. 2004-10-05 Thien-Thi Nguyen * db-format.el (dbf-process-field): Delete func. (dbf-process-field-maybe): Incorporate `dbf-process-field'. 2004-10-05 Thien-Thi Nguyen * edb.texi (Defining new displaytypes): Add scadenza for `displaytype->displayspec'. 2004-10-05 Thien-Thi Nguyen * db-format.el (db-ds-displayed): Delete func. (display-record): Incorporate `db-ds-displayed'. 2004-10-05 Thien-Thi Nguyen * db-format.el (database-mode-line-format): Delete var. (database-mode): Incorporate `database-mode-line-format' value. 2004-10-04 Thien-Thi Nguyen * edb.texi (Debugging EDB): For `db-disable-debugging-support' and `db-debug-p', convert @vindex and @table entries to @defvar block. Also, remove all @vindex lines. 2004-10-04 Thien-Thi Nguyen * edb.texi (Exiting Emacs or saving files): For `db-databases', convert @vindex and @table entry to @defvar block. (Global variables): Move `db-databases' defvar here. 2004-10-04 Thien-Thi Nguyen * edb.texi (Hooks and customization features): Refer to "File Variables" in the Emacs Manual directly. (Nonregular database example): Likewise. 2004-10-04 Thien-Thi Nguyen * edb.texi (Accessing record fields): Rewrite `dbf-set-this-record-modified-p' text. 2004-10-04 Thien-Thi Nguyen * edb.texi (Accessing record fields): Rewrite `dbf-displayed-record' text. 2004-10-04 Thien-Thi Nguyen * edb.texi (Mapping over the database): Remove @vindex for `maplinks-index' and `maplinks-link'. (Mapping over record fields): Remove @vindex for `mapfields-index' and `mapfields-field'. 2004-10-04 Thien-Thi Nguyen * edb.texi: Throughout, remove @vindex for `db-inform-interval' and `use-electric-help-p'. (Global variables): For `db-inform-interval' and `use-electric-help-p', convert @vindex and @table entries to @defvar blocks. 2004-10-04 Thien-Thi Nguyen * edb.texi (Display format change hooks): For `db-new-record-function', `dbf-first-change-function', `dbf-every-change-function', `dbf-change-functions' `dbf-set-this-record-modified-function' and `dbf-after-record-change-function', convert @vindex and @table entries to @defvar blocks. (Manipulating records): Remove @vindex for `db-new-record-function'. (Accessing record fields): Remove @vindex for `dbf-set-this-record-modified-function'. 2004-10-04 Thien-Thi Nguyen * edb.texi (Edit mode hooks): For `dbf-enter-field-hook' and `dbf-reset-on-edit-list', convert @vindex and @table entries into @defvar block. 2004-10-04 Thien-Thi Nguyen * edb.texi (Record display hooks): For `dbf-before-display-record-function', convert @vindex and @table entry into @defvar block. 2004-10-04 Thien-Thi Nguyen * edb.texi (Record display hooks): Remove @vindex for `dbf-format-name' and `db-format-file-path'. 2004-10-04 Thien-Thi Nguyen * edb.texi (Database minor mode hooks): For `db-view-mode-hooks', `db-edit-mode-hooks' and `database-summary-mode-hooks', convert @vindex and @table entries into @defvar blocks. 2004-10-04 Thien-Thi Nguyen * edb.texi (Load and read hooks): For `db-load-hooks', convert @vindex and @table entry into @defvar block, and add scadenza. 2004-10-04 Thien-Thi Nguyen * edb.texi (Auxiliary files): For `db-aux-file-suffixes', `db-aux-file-path', `db-format-file-suffixes' and `db-format-file-path', convert @vindex and @table entries into @defvar blocks. 2004-10-04 Thien-Thi Nguyen * edb.texi (Display specification optional parameters): No longer mention `dbm-string-prefix-regexp'. 2004-10-04 Thien-Thi Nguyen * edb.texi (Reading from disk): Remove @vindex for `db-before-read-hooks' and `db-after-read-hooks'. (Load and read hooks): For `db-before-read-hooks' and `db-after-read-hooks', convert @vindex and @table entries into @defvar blocks. (Accessing record fields): Remove @vindex for `db-after-read-hooks'. 2004-10-04 Thien-Thi Nguyen * edb.texi (Reading from disk): Remove @vindex for `inhibit-local-variables'. (Debugging EDB): Remove @vindex for `print-length', `print-level' and `debug-on-error'. 2004-10-04 Thien-Thi Nguyen * edb.texi (Tagged file layout): For `db-tagged-tag-chars', `db-tagged-separator', `db-tagged-separator-regexp', `db-tagged-separator-output', `db-tagged-continuation', `db-tagged-continuation-regexp', `db-tagged-continuation-output' `db-tagged-rrfr-hooks', `db-tagged-wrfr-before-hooks' and `db-tagged-wrfr-after-hooks', convert @vindex and @table entries into @defvar blocks. 2004-10-04 Thien-Thi Nguyen * edb.texi (The recordfieldspec structure): Remove @vindex for `dbf-field-priorities'. 2004-10-04 Thien-Thi Nguyen * edb.texi (Changing display formats): For `dbf-format-name-spec-alist', `dbf-format-name' and `dbf-format-file', convert @table entries into @defvar blocks. 2004-10-04 Thien-Thi Nguyen * edb.texi (Changing display formats): Remove @vindex for `dbf-before-display-record-function'. (Execution of format file eval expressions): Likewise. 2004-10-04 Thien-Thi Nguyen * edb.texi (Changing display formats): Remove @vindex for `dbf-format-name-spec-alist'. (Record display hooks): Likewise. 2004-10-04 Thien-Thi Nguyen * edb.texi (Details of hiding): For `dbc-hide-p', use @defvar. For `dbc-set-hide-p', delete @findex and add @defun. 2004-10-04 Thien-Thi Nguyen * edb.texi (Database Summary mode): For `dbf-summary-function', remove @vindex and add scadenza. For `dbf-summary-show-hidden-records-p' convert @table entry to @defvar block. 2004-10-04 Thien-Thi Nguyen * edb.texi (Sorting): For `dbsi-hidden-to-end-p', remove @vindex and add scadenza. For `dbf-field-priorities', `dbf-hidden-to-end-p' and `db-sort-modifies-p', convert @table entries to independent @defvar blocks. 2004-10-04 Thien-Thi Nguyen * edb.texi (Details of hiding): Add scadenza for `dbc-hide-p'. Rework references to say "enable hiding" or "disable hiding". (Debugging EDB): Add scadenza for "enabling debugging messages". 2004-10-04 Thien-Thi Nguyen * edb.texi: Throughout, do not quote "local variables". Also, convert some tex-style quotes to either @dfn or @code. 2004-10-04 Thien-Thi Nguyen * edb.texi (Organization of this manual): Mention instability of documentation for implementation details. Define macro `scadenza'. 2004-10-03 Thien-Thi Nguyen * edb.texi: Throughout, use @deffn, @defun and @defmac. (Invoking EDB): Remove `find-file' hackery. 2004-10-01 Thien-Thi Nguyen * db-time.el (integer->weekday): Delete defsubst. (date->weekday-name): Incorporate `integer->weekday'. 2004-10-01 Thien-Thi Nguyen * db-time.el (monthname->integer): Delete defsubst. (parse-date-string): Incorporate `monthname->integer'. 2004-10-01 Thien-Thi Nguyen * db-time.el (integer->monthname): Delete defsubst. (parse-date-string): Incorporate `integer->monthname'. (format-date-sub-syms-alist): Likewise. 2004-10-01 Thien-Thi Nguyen * db-time.el (integer->monthabbrev): Delete defsubst. (format-date-sub-syms-alist): Incorporate `integer->monthabbrev'. 2004-09-30 Thien-Thi Nguyen * ANONCVS: Specify "-d ..." explicitly for "cvs co". Suggested by Janusz S. Bieñ. 2004-09-30 Thien-Thi Nguyen * db-time.el (db-make-empty-time): Rename from `make-empty-time'. (db-time-default-constraint): Rename from `time-default-constraint'. (db-time-order): Rename from `time-order'. (db-time-match-function): Rename from `time-match-function'. (db-time->storage-string): Rename from `time->storage-string'. (db-storage-string->time): Rename from `storage-string->time'. (db-time-merge): Rename from `time-merge'. (parse-time-string): Use new names. (time): For this recordfieldtype, use new names. 2004-09-30 Thien-Thi Nguyen * db-time.el (monthname-regexp): Delete defconst. (weekday-regexp): Likewise. (monthnumber-regexp): Likewise. (monthnumber-regexp-two-char): Likewise. (monthday-regexp): Likewise. (monthday-regexp-two-char): Likewise. (full-year-regexp): Likewise. (short-year-regexp): Likewise. (year-regexp): Likewise. (db-elt-separator-regexp): Likewise. (date-regexps): Incorporate values of deleted defconsts. 2004-09-30 Thien-Thi Nguyen * Makefile.in (distfiles): Add PLANS. 2004-09-30 Thien-Thi Nguyen * db-time.el (date-order-within-year): Delete func. (date-order-absolute): Incorporate `date-order-within-year'. 2004-09-30 Thien-Thi Nguyen * db-time.el (date-month-day-compatible): Delete func. (parse-date-string): Incorporate `date-month-day-compatible'. 2004-09-30 Thien-Thi Nguyen * db-time.el (monthlength-array): Delete defconst. (date-month-day-compatible): Incorporate `monthlength-array'. 2004-09-30 Thien-Thi Nguyen * db-time.el (date->weekday-abbrev): Delete defsubst. (format-date-sub-syms-alist): Incorporate `date->weekday-abbrev'. 2004-09-30 Thien-Thi Nguyen * db-time.el (integer->weekday-abbrev): Delete unused func. 2004-09-30 Thien-Thi Nguyen * db-time.el (weekday-alist): Delete defconst. (weekday-regexp): Incorporate `weekday-alist'. 2004-09-30 Thien-Thi Nguyen * db-time.el (weekday-array): Delete defconst. (integer->weekday): Incorporate `weekday-array'. 2004-09-30 Thien-Thi Nguyen * db-time.el (leap-year-p): Delete func. (date->day-of-year): Incorporate `leap-year-p'. 2004-09-30 Thien-Thi Nguyen * db-time.el (date-year-short): Delete func. (format-date-sub-syms-alist): Incorporate `date-year-short'. 2004-09-30 Thien-Thi Nguyen * db-time.el (zero-or-empty-date-p): Delete func. (parse-date-string): Incorporate `zero-or-empty-date-p'. 2004-09-30 Thien-Thi Nguyen * db-time.el (db-make-empty-date): Rename from `make-empty-date'. (parse-date-string): Use` db-make-empty-date'. (parse-date-string-or-nil): Likewise. (date): For this recordfieldtype, use `db-make-empty-date'. 2004-09-30 Thien-Thi Nguyen * PLANS: New file. 2004-09-18 Thien-Thi Nguyen * edb.texi (EDB support): Delete node. (In case of trouble): Promote to chapter. 2004-09-17 Thien-Thi Nguyen * edb.texi: Remove @need directives. 2004-09-17 Thien-Thi Nguyen * edb.texi (Installing EDB): Delete node/section. (Updates to EDB): Likewise. (Compiling EDB): Delete node/subsection. 2004-09-17 Thien-Thi Nguyen * edb.texi (The database structure): Remove alist rationalization. 2004-09-17 Thien-Thi Nguyen * edb.texi (Resolving ambiguities): No longer mention FileMaker. 2004-09-17 Thien-Thi Nguyen * db-file-io.el (database-generate-delimiter): Fix bug introduced during locals name munging: Return non-nil result. 2004-09-17 Thien-Thi Nguyen * db-format.el (db-setup-ddb-parse-displayspecs): Replace `replace-string' with `(while (search-forward...) ...)'. * db-file-io.el (database-substitute-for-read): Likewise. (database-substitute-for-write): Likewise. * db-util.el (db-buffer-substitute): Likewise. 2004-09-17 Thien-Thi Nguyen * database.el (byte-compile-database): No longer hide byte-compiler warnings. 2004-09-17 Thien-Thi Nguyen * edb.texi: Colon-space cleanup. Reword to avoid "user". Zonk edb-inst.info references. Say "load database into memory" instead of "start database". Remove autoload instructions for `load-database' and `byte-compile-database'. Add some [fixme ...] comments. Use @dfn in some places. Grammar fixes. 2004-09-17 Thien-Thi Nguyen * database.el (db-log): Delete func. (db-message): Incorporate `db-log'. 2004-09-17 Thien-Thi Nguyen * database.el (edb-version): Return string unconditionally. 2004-09-17 Thien-Thi Nguyen * database.el (db-displaytypes): Init as hash table. * db-types.el (define-displaytype-from-displayspec): Handle `db-displaytypes' as hash table. * db-format.el (displaytype->displayspec): Handle `db-displaytypes' as hash table. 2004-09-17 Thien-Thi Nguyen * database.el (db-recordfieldtypes): Init as hash table. * db-file-io.el (recordfieldtype->recordfieldspec): Handle `db-recordfieldtypes' as hash table. (recordfieldtype-p): Delete func. * db-rep.el (database-set-fieldnames-to-list): No longer use `recordfieldtype-p'. Instead, consult `db-recordfieldtypes' directly. * db-types.el (define-recordfieldtype-from-recordfieldspec): Handle `db-recordfieldtypes' as hash table. 2004-09-17 Thien-Thi Nguyen * db-search.el (db-parse-match-object): Delete func. (db-parse-match-pattern): Incorporate `db-parse-match-object'. 2004-09-17 Thien-Thi Nguyen * db-search.el (db-print-match-object): Delete func. (db-print-match-pattern): Incorporate `db-print-match-object'. 2004-09-17 Thien-Thi Nguyen * edb.texi: Remove superfluous "\input texinfo". Also, remove many commented-out sections. 2004-09-17 Thien-Thi Nguyen * database.el (db-prepare-to-debug): Delete func. (db-debug): Delete macro. (db-debug-p): Delete var. (db-disable-debugging-support): Likewise. * db-format.el (db-parse-buffer-error): No longer use `db-debug-p'. (db-setup-data-display-buffer): Likewise. (display-record): Likewise. * db-file-io.el (db-write-1): Likewise. (database-confirm-fieldsep-and-recordsep): Likewise. 2004-09-17 Thien-Thi Nguyen * edb.texi (Debugging EDB): Bifurcate pre- and post-1.24. 2004-09-17 Thien-Thi Nguyen * edb.texi (Terminology): Add @dfn. Mention `fieldtype'. 2004-09-17 Thien-Thi Nguyen * database.el (db-debug-log): Delete macro. 2004-09-17 Thien-Thi Nguyen * database.el (db-debug-message): Delete macro. * db-format.el (db-actual->display-call): No longer use `db-debug-message'. (db-jump-to-point): Likewise. (dbf-process-field): Likewise. (dbf-redisplay-entire-record-maybe): Likewise. (make-displayspec-from-string-internal): Likewise. (db-setup-data-display-buffer): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. * db-interfa.el (db-save-database): Likewise. (db-write-database-file): Likewise. (db-select-record): Likewise. (db-search-field): Likewise. * db-file-io.el (db-read-database-file): Likewise. (db-choose-format-file): Likewise. (db-read-database-file-helper): Likewise. (database-set-links-from-list): Likewise. (db-reading-noninternal): Likewise. (db-read-file-custom): Likewise. (db-read-file-delimited): Likewise. (database-stored->actual-internal): Likewise. (database-delete-pre-and-post): Likewise. (db-write-1): Likewise. (db-write-intdelim): Likewise. (database-io-setup): Likewise. (database-substitute-for-read): Likewise. (database-substitute-for-write): Likewise. (database-confirm-fieldsep-and-recordsep): Likewise. * db-time.el (parse-date-string): Likewise. (format-date): Likewise. * db-rep.el (database-set-modified-p): Likewise. (database-set-fieldnames-to-list): Likewise. (database-add-record): Likewise. (maplinks-macro): Likewise. * db-summary.el (dbf-fill-summary-buffer): Likewise. * db-sort.el (database-sort): Likewise. (db-with-orderer): Likewise. (dbsi-prev-cons): Likewise. (dbsi-use-ordering-make-buffer-default): Likewise. * db-two-dbs.el (db-process-two-databases): Likewise. (db-merge): Likewise. * db-search.el (db-parse-match-object): Likewise. (db-match): Likewise. 2004-09-16 Thien-Thi Nguyen * db-format.el (db-dt-leading-comma-optional): Rename from `displaytype-leading-comma-optional'. (db-dtrx): Rename from `displaytype-regexp'. Also, use `db-dt-leading-comma-optional'. (db-foptrx): Use `db-dtrx'. (make-displayspec-from-type-and-options): Likewise. 2004-09-16 Thien-Thi Nguyen * db-format.el (db-dsrx): Rename from `displayspec-regexp'. (db-dsrx-fieldname): Rename from `displayspec-regexp-fieldname'. (db-dsrx-fieldoptions): Rename from `displayspec-regexp-fieldoptions'. (db-dsrx-content-beginning): Rename from `displayspec-regexp-content-beginning'. (db-dsrx-content-end): Rename from `displayspec-regexp-content-end'. (db-dsrx-content-end-alt): Rename from `displayspec-regexp-content-end-alt'. (displaytype->displayspec): Use new names. (make-displayspec-from-string-internal): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. * db-summary.el (db-format->lines/sforms): Use `db-dsrx', `db-dsrx-content-beginning', `db-dsrx-content-end' and `db-dsrx-content-end-alt'. 2004-09-16 Thien-Thi Nguyen * db-format.el (displayspec-set-reachable): Delete unused defsubst. 2004-09-16 Thien-Thi Nguyen * db-format.el (right-justify-slotsetter-function): Delete func. (db-optspec-list): Incorporate `right-justify-slotsetter-function'. 2004-09-16 Thien-Thi Nguyen * db-format.el (db-pad-right): Rename from `left-justify-padding-function'. (db-ds-printed): Use `db-pad-right'. 2004-09-16 Thien-Thi Nguyen * db-format.el (db-space-maybe-rx): Rename from `space-maybe-regexp'. (db-unindentify): Use `db-space-maybe-rx'. (db-beginning-of-line-or-field): Likewise. (db-forward-char): Likewise. (db-backward-char): Likewise. (db-kill-line): Likewise. 2004-09-16 Thien-Thi Nguyen * db-format.el (space-maybe-regexp-limit): Delete var. (space-maybe-regexp): Use number 8 directly. 2004-09-16 Thien-Thi Nguyen * db-format.el (db-string->displaytype): Rename from `string->displaytype'. (displaytype->displayspec): Use `db-string->displaytype'. (make-displayspec-from-type-and-options): Likewise. 2004-09-16 Thien-Thi Nguyen * db-format.el (dbf-set-buffer-local-variables): Delete func. (db-setup-data-display-buffer): Incorporate `dbf-set-buffer-local-variables'. 2004-09-16 Thien-Thi Nguyen * db-format.el (db-ds-printed): Rename from `displayspec->printed-rep'. (display-record): Use `db-ds-printed'. (db-ds-displayed): Likewise. * db-summary.el (db-format->lines/sforms): Use `db-ds-printed'. 2004-09-16 Thien-Thi Nguyen * db-format.el (db-ds-displayed): Rename from `displayspec->displayed-rep'. (dbf-process-field): Use `db-ds-displayed'. 2004-09-15 Thien-Thi Nguyen * db-isbn.el (db-isbn-constraint): Use `unless'. 2004-09-13 Thien-Thi Nguyen * db-types.el (string-or-nil->number-or-nil): Delete func and accompanying `make-obsolete' form. * db-time.el (parse-date-string): Incorporate `string-or-nil->number-or-nil'. 2004-09-13 Thien-Thi Nguyen * db-types.el (db-enum-make-help-info): Delete func. (db-enum-make-display->actual): Likewise. (db-enum-do-completions): Likewise. (db-enum-make-actual->display): Likewise. (db-enum-make-actual->stored): Likewise. (make-enum-member-orderer): Likewise. (make-enum-member-sorter): Likewise. (make-enum-member-orderer-internal): Likewise. (define-enum-type): Incorporate `db-enum-make-help-info', `db-enum-make-display->actual', `db-enum-do-completions', `db-enum-make-actual->display', `db-enum-make-actual->stored', `make-enum-member-orderer', `make-enum-member-sorter', `make-enum-member-orderer-internal'. 2004-09-13 Thien-Thi Nguyen * db-format.el (db-setup-data-display-buffer): Fix bug introduced in last change: Use `file-name-sans-extension'. 2004-09-13 Thien-Thi Nguyen * db-types.el (db-enum-make-help-info): Use `with-temp-buffer'. * db-util.el (db-unused-char-in-string): Likewise. 2004-09-13 Thien-Thi Nguyen * db-types.el (db-enum-process-alternatives): Delete func. (define-enum-type): Incorporate `db-enum-process-alternatives'. 2004-09-13 Thien-Thi Nguyen * db-file-io.el (load-db-aux-file): Delete func. * db-format.el (db-setup-data-display-buffer): Incorporate `load-db-aux-file'. 2004-09-13 Thien-Thi Nguyen * db-util.el (db-if-file-readable-p): Delete defsubst. (db-locate-file-with-extensions): Delete func. (db-locate-file-with-extensions-on-path): Likewise. (db-locate-file-on-path): Likewise. * db-file-io.el (db-file->format-file): Use `locate-file'. (db-locate-format-file): Likewise. (load-db-aux-file): Likewise. 2004-09-13 Thien-Thi Nguyen * db-util.el (db-filename-extension-regexp): Delete var. (db-filename-sans-extension): Delete func. (db-locate-file-with-extensions): Use `file-name-sans-extension'. * db-file-io.el (db-choose-format-file): Use `file-name-sans-extension'. 2004-09-13 Thien-Thi Nguyen * db-interfa.el (db-save-some-databases): Use `with-current-buffer' instead of `db-in-buffer' where body is side-effect free. (db-find-file): Likewise. * db-summary.el (db-summary): Likewise. (dbs-synch-format-with-summary): Likewise. * db-two-dbs.el (db-merge): Likewise. (db-merge-records): Likewise. * db-sort.el (dbsi-use-ordering-make-database-default): Use `with-current-buffer' instead of `db-in-buffer' where body does not change display. 2004-09-13 Thien-Thi Nguyen * database.el (db-log): Locals name munging; nfc. (db-message): Likewise. (db-warning): Likewise. (db-debug-log): Likewise. (db-debug-message): Likewise. (db-prepare-to-debug): Likewise. (load-database): Likewise. (byte-compile-database-all): Likewise. (byte-compile-database): Likewise. 2004-09-13 Thien-Thi Nguyen * db-time.el (test-date-formats): Comment out func. (leap-year-p): Locals name munging; nfc. (date->absolute-days): Likewise. (monthname->integer): Likewise. (integer->monthname): Likewise. (integer->monthabbrev): Likewise. (date-order-absolute): Likewise. (date-order-within-year): Likewise. (parse-date-string): Likewise. (parse-date-string-or-nil): Likewise. (parse-date-default-function): Likewise. (format-date): Likewise. (date-match-function): Likewise. (date-merge): Likewise. (storage-string-mmddyyyy->date): Likewise. (storage-string-lisp->date): Likewise. (date-stored->actual): Likewise. (time-default-constraint): Likewise. (parse-time-string): Likewise. (parse-time-default-function): Likewise. (time-order): Likewise. (time-match-function): Likewise. (storage-string->time): Likewise. (time-merge): Likewise. 2004-09-13 Thien-Thi Nguyen * db-types.el (db-boolean->yn-string): Rename from `boolean->yn-string'. (db-yn-string->boolean): Rename from `yn-string->boolean'. (db-boolean-order-function): Rename from `boolean-order-function'. (db-boolean-lessp): Rename from `db-boolean-lessp'. (boolean): For this recordfieldtype, use new names. 2004-09-13 Thien-Thi Nguyen * db-types.el (string-is-yn-p): Delete unused func. 2004-09-13 Thien-Thi Nguyen * db-types.el (db-boolean->yes-no-string): Rename from `boolean->yes-no-string'. (db-yes-no-string->boolean): Rename from `yes-no-string->boolean'. (yes-no): For this displaytype, use new names. 2004-09-13 Thien-Thi Nguyen * db-rdb.el (db-rdb-p): Locals name munging; nfc. (db-rdb-setup-internal): Likewise. (db-rdb-list-rrfr): Likewise. (db-rdb-list-wrfr): Likewise. (db-rdb-lookup-field): Likewise. (db-rdb-read-list-field-defs): Likewise. (db-rdb-correlate-field-defs): Likewise. 2004-09-12 Thien-Thi Nguyen * db-tagged.el (db-tagged-spec-name): Rename from `tagged-field-spec-name'. (db-tagged-spec-tag): Rename from `tagged-field-spec-tag'. (db-tagged-spec-help): Rename from `tagged-field-spec-help'. (db-tagged-setup-internal): Use new names. (db-tagged-wrfr): Likewise. 2004-09-12 Thien-Thi Nguyen * db-tagged.el (db-tagged-setup): Locals name munging; nfc. (db-tagged-setup-internal): Likewise. (db-tagged-before-read): Likewise. (db-tagged-rrfr): Likewise. (db-tagged-wrfr): Likewise. 2004-09-12 Thien-Thi Nguyen * db-two-dbs.el (db-process-two-databases): Locals name munging; nfc. (db-merge-internal): Likewise. (db-merge): Likewise. (db-merge-records): Likewise. (db-choose-value): Likewise. (db-read-fieldvalue-from-minibuffer): Likewise. (databases-compatible): Likewise. (database-compare-hack): Likewise. 2004-09-12 Thien-Thi Nguyen * db-isbn.el (db-isbn-constraint): Locals name munging; nfc. 2004-09-12 Thien-Thi Nguyen * db-util.el (db-unused-char-in-buffer): Locals name munging; nfc. (db-unused-char-in-string): Likewise. (db-skip-string-forward): Likewise. (db-skip-string-backward): Likewise. (db-skip-regexp-forward): Likewise. (db-skip-regexp-backward): Likewise. (db-looking-back-at): Likewise. (db-how-many-string-overlapping): Likewise. (db-how-many-substring-overlapping): Likewise. (db-find-char): Likewise. (db-find-char-from-end): Likewise. (db-string-trim-whitespace): Likewise. (db-vararg-call): Likewise. (db-locate-file-with-extensions): Likewise. (db-locate-file-with-extensions-on-path): Likewise. (db-same-file-p): Likewise. (db-string->integer-default): Likewise. (db-string->integer-or-nil): Likewise. (db-string->integer): Likewise. (db-number-or-nil->string): Likewise. (db-in-buffer): Likewise. (db-copy-buffer-local-variables): Likewise. (db-string-split-last-word): Likewise. (db-string-split-first-word): Likewise. (db-count-newlines): Likewise. (db-best-fit-message): Likewise. (db-forward-line-wrapping): Likewise. (db-buffer-substitute): Likewise. (db-operate-on-local-variables): Likewise. 2004-09-12 Thien-Thi Nguyen * db-types.el (name->first-last-jr): Fix typo. 2004-09-12 Thien-Thi Nguyen * db-types.el (define-displaytype-from-optstring): Locals name munging; nfc. (define-type-alias): Likewise. (db-enum-process-alternatives): Likewise. (db-enum-do-completions): Likewise. (make-enum-member-orderer-internal): Likewise. (string-or-nil->number-or-nil): Likewise. (boolean->yes-no-string): Likewise. (yes-no-string->boolean): Likewise. (boolean->yn-string): Likewise. (yn-string->boolean): Likewise. (string-is-yn-p): Likewise. (boolean-order-function): Likewise. (boolean-lessp): Likewise. (string-lessp-ci): Likewise. (string-order-ci): Likewise. (make-regexp-pattern): Likewise. (regexp-pattern-regexp): Likewise. (make-string-pattern): Likewise. (string-pattern-regexp): Likewise. (string-pattern-string): Likewise. (string-match-function): Likewise. (string-match-display->actual): Likewise. (string-match-actual->display): Likewise. (string-or-nil-lessp-ci): Likewise. (string-or-nil-order-ci): Likewise. (string-or-nil-match-function): Likewise. (string->nil-or-string): Likewise. (order-last-names): Likewise. (canonicalize-name): Likewise. (same-first-name-p): Likewise. (order-first-names): Likewise. (name->first-last-jr): Likewise. (postal-code-p): Likewise. (statep): Likewise. 2004-09-12 Thien-Thi Nguyen * db-types.el (string-lessp-ci): Use `compare-strings'. (string-order-ci): Likewise. 2004-09-12 Thien-Thi Nguyen * db-isbntst.el: Delete file. * Makefile.in (TEST-EL-FILES): Delete var. (TAGS): No longer depend on $(TEST-EL-FILES). Also, in actions, use `$^' directly. * HACKING (Implementation Organization): Remove db-isbntst.el. 2004-09-12 Thien-Thi Nguyen * skram/make-hacksup.el: No longer change default directory. Init `files' from `command-line-args-left' directly. * skram/make-skram.el: Init from `command-line-args-left' directly. * skram/GNUmakefile (all): Also depend on hacksup.el. (hacksup.el): New target. (skram.data): Use `$^' directly. (clean): Also delete "*~". (realclean): Also delete hacksup.el. * Makefile.in (clean): Recurse into subdir `skram'. (hacksup.el): Delete target. (distfiles): Remove hacksup.el. 2004-09-11 Thien-Thi Nguyen * db-interfa.el (database-view-mode-map): Fix typo. 2004-09-11 Thien-Thi Nguyen * db-file-io.el (db-write-1): Rename from `write-database-file'. * db-interfa.el (db-write-database-file): Use `db-write-1'. 2004-09-11 Thien-Thi Nguyen * db-file-io.el (db-write-intdelim): Rename from `write-database-file-internal-delimited'. (write-database-file): Use `db-write-intdelim'. 2004-09-11 Thien-Thi Nguyen * db-isbn.el (db-isbn-constraint): Rename from `isbn-constraint'. (isbn): For this recordfieldtype, use `db-isbn-constraint'. 2004-09-11 Thien-Thi Nguyen * tests: New subdir. * Makefile.in (check): Recurse into tests. * configure.ac (AC_CONFIG_FILES): Add tests/Makefile. 2004-09-10 Thien-Thi Nguyen * Makefile.in (clean): No longer remove "*.survey". (distfiles): Remove def.survey, def-indexed.survey and def-undoc.survey. (surveys): Delete target. (def-undoc.survey): Likewise. (def-indexed.survey): Likewise. (def.survey): Likewise. (info-stdout): Delete var. * skram/make-skram.el: New file. * skram/GNUmakefile (ebatch): New var. (skram.data): Rewrite. (wily-emacs): Use $(ebatch). 2004-09-10 Thien-Thi Nguyen * db-format.el (db-optspec-list): Use `db-string->number'. * db-types.el (string-or-nil->number-or-nil): Use `db-string->number-or-nil'. (number-or-nil): Likewise for this displaytype definition and recordfieldtype definition by the same name. 2004-09-10 Thien-Thi Nguyen * db-sort.el (db-convert-ordering-fields): Locals name munging; nfc. (db-make-ordering-fields-canonical): Likewise. (db-order-records): Likewise. (db-record-lessp): Likewise. (database-sorted-p): Likewise. (database-ordered-p): Likewise. (db-with-orderer): Likewise. (db-with-sorter): Likewise. (database-sort-interface): Likewise. (dbsi-prev-cons): Likewise. (dbsi-toggle-hidden-to-end): Likewise. (dbsi-quit): Likewise. (dbsi-quit-clear-buffer-default): Likewise. (dbsi-use-ordering): Likewise. (dbsi-this-field-only): Likewise. 2004-09-10 Thien-Thi Nguyen * db-sort.el (database-no-identical-keys-p): Delete unused func. 2004-09-10 Thien-Thi Nguyen * db-sort.el (db-converted-ofields): Rename from `ordering-fields-converted'. (database-sort): Use `db-converted-ofields'. (db-order-records): Likewise. (db-with-orderer): Likewise. (db-with-sorter): Likewise. 2004-09-10 Thien-Thi Nguyen * database.el (db-warn): Delete fset. 2004-09-09 Thien-Thi Nguyen * db-interfa.el (db-commit-record): Use `defalias', not `fset'. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-string->integer): Rename from `string->integer'. Convert associated `fset' form to `defalias'. Also, rename the alias to `db-string->number' from `string->number'. * db-time.el (storage-string-mmddyyyy->date): Use `db-string->integer'. (storage-string->time): Likewise. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-string->integer-or-nil): Rename from `string->integer-or-nil'. Convert associated `fset' form to `defalias'. Also, rename the alias to `db-string->number-or-nil' from `string->number-or-nil'. (string->integer): Use `db-string->integer-or-nil'. * db-types.el (integer-or-nil): For this displaytype, use `db-string->integer-or-nil'. Likewise for recordfieldtype of the same name. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-string->integer-default): Rename from `string->integer-default'. Convert associated `fset' form to `defalias'. Also, rename the alias to `db-string->number-default' from `string->number-default'. (string->integer-or-nil): Use `db-string->integer-default'. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-number-or-nil->string): Rename from `number-or-nil->string'. Remove associated `make-obsolete' form. * db-types.el (integer-or-nil): For this displaytype, use `db-number-or-nil->string'. Likewise for recordfieldtype of the same name. (number-or-nil): Likewise for this displaytype/recordfieldtype pair. 2004-09-09 Thien-Thi Nguyen * db-rdb.el (db-rdb-fspec-handle): Rename from `rdb-field-spec-handle'. (db-rdb-fspec-name): Rename from `rdb-field-spec-name'. (db-rdb-fspec-type): Rename from `rdb-field-spec-type'. (db-rdb-fspec-tag): Rename from `rdb-field-spec-tag'. (db-rdb-fspec-help): Rename from `rdb-field-spec-help'. (db-rdb-setup-internal): Use new names. (db-rdb-list-wrfr): Likewise. 2004-09-09 Thien-Thi Nguyen * db-isbn.el (SFf-isbn-check-sum): Delete func. (isbn-constraint): Incorporate `SFf-isbn-check-sum'. 2004-09-09 Thien-Thi Nguyen * Makefile.in (def-indexed.survey): Avoid "/" in sed expression. 2004-09-09 Thien-Thi Nguyen * db-summary.el (mode-motion-hook): Delete var. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-count-array): Delete func. (db-count-newlines): New func. * db-format.el (displayspec->printed-rep): Use `db-count-newlines'. * db-summary.el (db-format->lines/sforms): Likewise. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-string-split-last-word): No longer take optional third arg `delimiter'. (db-string-split-first-word): Likewise for second arg. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-string-substitute): Delete func. (db-string-substitute-opt): Likewise. * db-summary.el (db-format->lines/sforms): Use `subst-char-in-string'. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-string-substitute-substring-general-case): Delete func. * db-file-io.el (database-substitute-for-read): Use `replace-regexp-in-string'. * db-format.el (db-unindentify): Likewise. (display-record): Likewise. (displayspec->displayed-rep): Likewise. * db-summary.el (db-format->lines/sforms): Likewise. 2004-09-09 Thien-Thi Nguyen * db-util.el (db-string-replace-regexp-2): Delete func. (db-string-substitute-substring-general-case): Use `replace-regexp-in-string'. 2004-09-09 Thien-Thi Nguyen * db-summary.el (db-create-summary-buffer): Delete func. (db-summary): Incorporate `db-create-summary-buffer'. 2004-09-09 Thien-Thi Nguyen * db-summary.el (dbf-summarize-link): Delete unused func. 2004-09-09 Thien-Thi Nguyen * db-summary.el (db-format->lines/sforms): Rename from `format->lines-and-stringform-list'. (dbf-make-summary-maker): Use `db-format->lines/sforms'. * db-interfa.el (db-report): Use `db-format->lines/sforms'. * database.el: Autoload `db-format->lines/sforms'. 2004-09-09 Thien-Thi Nguyen * db-summary.el (make-format-printer): Delete func. (format->lines-and-stringform-list): Incorporate `make-format-printer'. 2004-09-09 Thien-Thi Nguyen * db-summary.el (db-summary): Locals name munging; nfc. (db-create-summary-buffer): Likewise. (dbs-insert-link-summary): Likewise. (dbf-fill-summary-buffer): Likewise. (dbf-fill-summary-buffer-and-move-to-proper-record): Likewise. (dbf-update-summary-marks): Likewise. (dbf-update-summary-item): Likewise. (dbf-summarize-link): Likewise. (dbf-make-summary-maker): Likewise. (format->lines-and-stringform-list): Likewise. (dbs-move-to-proper-record): Likewise. (dbs-exit): Likewise. 2004-09-09 Thien-Thi Nguyen * skram/make-hacksup.el: Fix bug: For `defmacro', start `declare' search at fourth form element. 2004-09-09 Thien-Thi Nguyen * edb.texi (Invoking EDB): Add @cindex for Lucid. 2004-09-08 Thien-Thi Nguyen * db-file-io.el (record-sep-lines-function): Delete unused func. 2004-09-08 Thien-Thi Nguyen * db-rep.el (dbf-this-record-field): Delete unused defsubst. 2004-09-08 Thien-Thi Nguyen * db-rep.el (recordfieldspecs-compatible): Delete func. * db-two-dbs.el (databases-compatible): Incorporate `recordfieldspecs-compatible'. 2004-09-08 Thien-Thi Nguyen * db-two-dbs.el (db-read-fieldvalue-from-minibuffer): Rename from `read-fieldvalue-from-minibuffer'. (db-choose-value): Use `db-read-fieldvalue-from-minibuffer'. 2004-09-08 Thien-Thi Nguyen * db-file-io.el (db-read-database-file): Rename from `read-database-file'. * db-interfa.el (db-find-file): Use `db-read-database-file'. (db-revert-database): Likewise. 2004-09-08 Thien-Thi Nguyen * db-types.el (db-number-or-nil-order-nil-least): Rename from `number-or-nil-order-nil-least'. 2004-09-08 Thien-Thi Nguyen * db-types.el (db-number-or-nil-order-nil-greatest): Rename from `number-or-nil-order-nil-greatest'. (integer-or-nil): For this recordfieldtype, use `db-number-or-nil-order-nil-greatest'. (number-or-nil): Likewise. * db-time.el (date-order-absolute): Use `db-number-or-nil-order-nil-greatest'. (date-order-within-year): Likewise. (time-order): Likewise. 2004-09-08 Thien-Thi Nguyen * db-types.el (db-number-order): Rename from `number-order'. (integer): For this recordfieldtype, use `db-number-order'. (number): Likewise. 2004-09-08 Thien-Thi Nguyen * db-format.el (fieldoptions-regexp): Delete defconst. (displayspec-regexp): Use `fieldoptions-regexp' value directly. 2004-09-08 Thien-Thi Nguyen * db-format.el (db-foptrx): Rename from `fieldoption-regexp'. (db-foptrx-symbol): Rename from `fieldoption-regexp-symbol'. (db-foptrx-equals): Rename from `fieldoption-regexp-equals'. (make-displayspec-from-type-and-options): Use new names. 2004-09-08 Thien-Thi Nguyen * db-file-io.el (db-choose-format-file): Rename from `choose-format-file'. (read-database-file): Use `db-choose-format-file'. * db-rep.el (make-similar-database): Use `db-choose-format-file'. 2004-09-08 Thien-Thi Nguyen * db-file-io.el (db-confls-fieldsep-bad-p): Rename from `conflist-fieldsep-bad-p'. (db-confls-recordsep-bad-p): Rename from `conflist-recordsep-bad-p'. (db-confls-no-of-records): Rename from `conflist-no-of-records'. (db-read-file-delimited): Use new names. (write-database-file-internal-delimited): Likewise. 2004-09-08 Thien-Thi Nguyen * db-format.el (db-optspec-list): Rename from `optspec-list'. (make-displayspec-from-type-and-options): Use `db-optspec-list'. 2004-09-08 Thien-Thi Nguyen * db-file-io.el (db-locate-format-file): Rename from `locate-format-file'. (choose-format-file): Use `db-locate-format-file'. * db-format.el (db-change-format): Use `db-locate-format-file'. 2004-09-08 Thien-Thi Nguyen * db-tagged.el (db-tagged-lookup-field): Rename from `lookup-field'. (db-tagged-rrfr): Use `db-tagged-lookup-field'. 2004-09-08 Thien-Thi Nguyen * db-format.el (db-unindentify): Rename from `unindentify'. (dbf-this-field-text-unrect): Use `db-unindentify'. (db-backward-word): Likewise. 2004-09-08 Thien-Thi Nguyen * db-time.el (db-elt-separator-regexp): Rename from `elt-separator-regexp'. (date-regexps): Use `db-elt-separator-regexp'. 2004-09-08 Thien-Thi Nguyen * db-interfa.el (data-display-buffer-database): Delete defsubst. (display-current-record): Likewise. 2004-09-08 Thien-Thi Nguyen * db-two-dbs.el (db-choose-value): Rename from `choose-value'. (db-merge-records): Use `db-choose-value'. 2004-09-07 Thien-Thi Nguyen * skram/make-hacksup.el: New file. * Makefile.in (hacksup.el): Rewrite to use skram/make-hacksup.el. 2004-09-07 Thien-Thi Nguyen * db-file-io.el (db-read-file-custom): Rename from `read-database-file-custom'. (db-read-file-delimstr): Rename from `read-database-file-delimited-string'. (db-read-file-delimrx): Rename from `read-database-file-delimited-regexp'. (db-read-file-delimited): Rename from `read-database-file-delimited'. Also, use `db-read-file-delimstr' and `db-read-file-delimrx'. (db-read-database-file-helper): Use `db-read-file-custom' and `db-read-file-delimited'. 2004-09-07 Thien-Thi Nguyen * db-file-io.el (db-read-database-file-helper): Rename from `read-database-file-helper'. (read-database-file): Use `db-read-database-file-helper'. * db-interfa.el (db-revert-database): Use `db-read-database-file-helper'. 2004-09-07 Thien-Thi Nguyen * db-file-io.el (db-read-database-internal-file-layout): Rename from `read-database-internal-file-layout-maybe'. Also, if buffer is not in valid format, return nil. (read-database-file): Use `db-read-database-internal-file-layout'. If it returns nil, call `make-database' directly. * db-interfa.el (db-revert-database): Use `db-read-database-internal-file-layout'. If it returns nil, signal error. 2004-09-06 Thien-Thi Nguyen * db-util.el (db-skip-string-forward): Rewrite. (db-skip-string-backward): Likewise. 2004-09-03 Thien-Thi Nguyen * db-format.el (update-displayspec-from-optspec-and-value): Delete func. (make-displayspec-from-type-and-options): Incorporate `update-displayspec-from-optspec-and-value'. 2004-09-03 Thien-Thi Nguyen * db-interfa.el (database-view-mode-map): Bind `S' to `db-sort'. 2004-09-03 Thien-Thi Nguyen * db-file-io.el (db-jam-si): Rename from `sepinfo-set-regexp-and-submatch-from-string'. Compute accessors at macroexpansion time. Update callers. 2004-09-03 Thien-Thi Nguyen * db-sort.el (db-with-pc): Rename from `with-pc'. Update callers. (db-with-pc-and-ti): Rename from `with-pc-and-ti'. Update callers. 2004-09-03 Thien-Thi Nguyen * db-sort.el (db-with-sorter): Rename from `with-sorter'. (database-sorted-p): Use `db-with-sorter'. 2004-09-03 Thien-Thi Nguyen * db-sort.el (db-with-orderer): Rename from `with-orderder'. * db-two-dbs.el (db-process-two-databases): Use `db-with-orderer'. 2004-09-03 Thien-Thi Nguyen * db-file-io.el (db-reading-noninternal): Rename from `read-database-file-noninternalformat-macro'. Update callers. 2004-09-03 Thien-Thi Nguyen * db-interfa.el (database-view-mode-map): Bind "F" to `dbf-set-summary-format'. 2004-09-03 Thien-Thi Nguyen * db-file-io.el (write-database-file): Say thanks. 2004-09-03 Thien-Thi Nguyen * db-isbn.el: Throughout, use new interface for `define-displaytype-from-displayspec' and `define-recordfieldtype-from-recordfieldspec'. * db-types.el: Likewise. * db-time.el: Likewise. (def-date-disptype): Delete func. Update callers to use `define-displaytype-from-displayspec' directly. (def-time-disptype): Likewise. 2004-09-03 Thien-Thi Nguyen * db-format.el (displayspec): For this defstruct, explicitly specify `:type' and `:named' options. For the symbol, add property `kwidx'. * db-rep.el (recordfieldspec): Likewise. * db-types.el (define-displaytype-from-displayspec): Accept new rest-argument `override'. Allow name, object or nil for second arg, now called `source'. Do templating. (define-recordfieldtype-from-recordfieldspec): Likewise. 2004-09-03 Thien-Thi Nguyen * db-types.el (define-displaytype-alias): Delete fset. (define-recordfieldtype-alias): Likewise. 2004-09-03 Thien-Thi Nguyen * db-search.el (dbm-and-connective): Delete var. (dbm-or-connective): Likewise. (dbm-not-prefix): Likewise. (dbm-<-prefix): Likewise. (dbm->-prefix): Likewise. (dbm-=-prefix): Likewise. (db-parse-match-pattern): Incorporate values of deleted vars. (db-parse-match-object): Locals name munging; nfc. (db-print-match-pattern): Likewise. (db-print-match-object): Likewise. (db-match): Likewise. 2004-09-03 Thien-Thi Nguyen * db-isbn.el (SFf-isbn-check-sum): Use `incf' and `decf'. * db-format.el (space-maybe-regexp): Use `decf'. * db-sort.el (dbsi-prev-cons): Use `decf'. * db-summary.el (format->lines-and-stringform-list): Use `incf'. * db-time.el (date->day-of-year): Use `decf'. 2004-09-03 Thien-Thi Nguyen * db-util.el (db-buffer-substitute): Use `push'. * db-types.el (define-displaytype-from-displayspec): Likewise. (define-recordfieldtype-from-recordfieldspec): Likewise. (db-enum-process-alternatives): Likewise. * db-summary.el (format->lines-and-stringform-list): Likewise. * db-sort.el (db-make-ordering-fields-canonical): Likewise. (dbsi-kill-line): Likewise. * db-format.el (db-copy-region-as-kill): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. (db-change-format): Likewise. * db-file-io.el (read-database-file-helper): Likewise. (database-stored->actual-internal): Likewise. * db-convert.el (db-convert-compute-field-value): Likewise. * database.el: Likewise. 2004-09-03 Thien-Thi Nguyen * db-file-io.el (read-database-file): Locals name munging; nfc. (db-file->format-file): Likewise. (choose-format-file): Likewise. (read-database-file-helper): Likewise. (database-set-links-from-list): Likewise. (read-database-file-custom): Likewise. (read-database-file-delimited): Likewise. (read-database-file-delimited-string): Likewise. (read-database-file-delimited-regexp): Likewise. (database-delete-pre-and-post): Likewise. (write-database-file): Likewise. (write-database-file-internal-delimited): Likewise. (database-io-setup): Likewise. (database-check-all-sepinfos): Likewise. (database-check-sepinfo): Likewise. (sepinfo-set-regexp-and-submatch-from-string): Likewise. (recordfieldtype->recordfieldspec): Likewise. (recordfieldtype-p): Likewise. (database-substitute-for-read): Likewise. (database-substitute-for-write): Likewise. (database-confirm-fieldsep-and-recordsep): Likewise. (database-acceptable-delimiter-p): Likewise. (database-generate-delimiter): Likewise. 2004-09-03 Thien-Thi Nguyen * Makefile.in (def.survey): Filter "^.define-", not "define-key". 2004-09-02 Thien-Thi Nguyen * db-file-io.el (database-set-temp-delimiters): Delete func. 2004-09-02 Thien-Thi Nguyen * db-convert.el (db-canonicalize-creation-methods): Delete func. (db-convert): Incorporate `db-canonicalize-creation-methods'. 2004-09-02 Thien-Thi Nguyen * db-convert.el (creation-method-literal-p): Delete defsubst. Update callers to test argument directly. 2004-09-02 Thien-Thi Nguyen * db-convert.el (creation-method-literal-p): Locals name munging; nfc. (db-convert): Likewise. (db-convert-record): Likewise. (db-convert-compute-field-value): Likewise. (db-canonicalize-creation-methods): Likewise. (db-canonicalize-creation-method): Likewise. 2004-09-02 Thien-Thi Nguyen * db-convert.el (db-computed-functions): Rename var from `computed-functions'. Update all use-sites. 2004-09-02 Thien-Thi Nguyen * db-types.el: Throughout, use keyword args to `make-displayspec' and `make-recordfieldspec'. 2004-09-02 Thien-Thi Nguyen * db-types.el: Add scope to test for Emacs 19.28 `string-to-number' bug and choose a correct variant. (string-to-number-trim): Delete func. Move callers into test/choice scope; use the correct variant. 2004-09-02 Thien-Thi Nguyen * db-types.el (country-list): Delete var. (countryp): Delete func. 2004-09-02 Thien-Thi Nguyen * db-rep.el (read-sep-items): Delete func. (write-sep-items): Likewise. 2004-09-02 Thien-Thi Nguyen * db-rep.el (db-next-link-and-index): Rename from `next-link-and-index'. (database-add-record): Use `db-next-link-and-index'. * db-interfa.el (db-select-next-record): Use `db-next-link-and-index'. * db-summary.el (dbf-update-summary-item): Likewise. 2004-09-02 Thien-Thi Nguyen * db-rep.el (print-database): Delete func. (print-record): Likewise. (print-compare-records): Likewise. * db-two-dbs.el (database-compare-hack): Incorporate `print-record' and `print-compare-records'. 2004-09-02 Thien-Thi Nguyen * db-format.el (db-x-jump-to-point): Delete defsubst. * db-interfa.el: No longer bind "\C-x\C-@". * db-summary.el (database-summary-mode-map): No longer bind "\C-x\C-@". 2004-09-02 Thien-Thi Nguyen * db-lemacs.el: New file. * database.el (db-running-lucid-emacs): Delete var. * db-format.el (db-fontification): Delete var. (db-display-record-redo-inter-field-text-function): New 2-arg hook var. (display-record): Run new hook in place of former `db-fontification'-conditionalized frags. (db-inter-field-face): Delete face init. (db-fontify): Delete func. * db-interfa.el: Delete Lucid-specific keymap inits. (db-lucid-mouse-jump-to-point): Delete func. (dbs-lucid-mouse-view): Likewise. * db-summary.el: Delete Lucid-specific keymap and other inits. * edb.texi (Invoking EDB): Mention db-lemacs.el. * Makefile.in (EL-FILES): Add db-lemacs.el. 2004-09-02 Thien-Thi Nguyen * db-format.el (db-symbol-regexp): Rename from `symbol-regexp'. Update use-sites. 2004-09-02 Thien-Thi Nguyen * db-format.el (actual->display-error-string): Delete var. (db-actual->display-call): Rename from `actual->display-call'. Also, incorporate `actual->display-error-string'. (displayspec->printed-rep): Use `db-actual->display-call'. * db-interfa.el: Use `db-actual->display-call'. * db-search.el: Likewise. * db-two-dbs.el: Likewise. 2004-09-02 Thien-Thi Nguyen * db-format.el (db-display->actual-call): Rename from `display->actual-call'. (dbf-process-field): Use `db-display->actual-call'. * db-interfa.el: Use `db-display->actual-call'. * db-search.el: Likewise. * db-two-dbs.el: Likewise. 2004-09-02 Thien-Thi Nguyen * db-format.el (opspectinfo-param-name): Delete func. (optspecinfo-settor): Likewise. (optspecinfo-param->value): Likewise. (update-displayspec-from-optspec-and-value): Incorporate `optspecinfo-settor' and `optspecinfo-param->value'. 2004-09-02 Thien-Thi Nguyen * db-format.el (doubled-backslash-regexp): Delete defconst. (non-backslash-character-regexp): Likewise. (symbol-or-number-regexp): Likewise. (fieldname-regexp): Likewise. (displaytype-nonsymbol-regexp): Likewise. (displaytype-regexp): Incorporate `displaytype-nonsymbol-regexp'. (fieldoption-regexp): Incorporate `symbol-or-number-regexp'. (displayspec-regexp): Incorporate `fieldname-regexp'. 2004-09-02 Thien-Thi Nguyen * db-format.el (dbf-set-field-text): Delete func. (dbf-goto-field): Likewise. 2004-09-02 Thien-Thi Nguyen * db-format.el (right-justify-padding-function): Delete func. (return-right-justify-padding-function): Likewise. 2004-09-02 Thien-Thi Nguyen * db-format.el (ordinary-truncation-function): Delete func. (displayspec->printed-rep): Incorporate `ordinary-truncation-function'. 2004-09-02 Thien-Thi Nguyen * db-format.el (dbf-install-format-spec): Use `pop'. (dbf-install-format-file-spec): Likewise. 2004-09-02 Thien-Thi Nguyen * db-format.el (dbf-wraparound-p): Delete deflocalvar. 2004-09-02 Thien-Thi Nguyen * db-format.el (dbf-set-this-field-index): Delete defsubst. (db-view-mode): Set `dbf-this-field-index' and `dbf-this-displayspec' directly. 2004-09-02 Thien-Thi Nguyen * db-format.el (dbf-install-format-name-and-spec): Delete func. (dbf-format-name->spec): Likewise. (comma-delimited-string->list): Likewise. 2004-09-02 Thien-Thi Nguyen * db-format.el (dbf-fieldname->displayspecno): Locals name munging; nfc. (dbf-set-this-field-index): Likewise. (dbf-install-format-name-and-spec): Likewise. (dbf-format-name->spec): Likewise. (dbf-install-format-spec): Likewise. (format-spec-format-file): Likewise. (dbf-install-format-file-spec): Likewise. (left-justify-padding-function): Likewise. (right-justify-padding-function): Likewise. (ordinary-truncation-function): Likewise. (db-edit-mode): Likewise. (db-next-field-internal): Likewise. (db-previous-field-internal): Likewise. (db-copy-region-as-kill): Likewise. (db-newline): Likewise. (dbf-process-field-maybe): Likewise. (dbf-process-field): Likewise. (string->displaytype): Likewise. (displaytype->displayspec): Likewise. (comma-delimited-string->list): Likewise. (make-displayspec-from-string): Likewise. (make-displayspec-from-string-internal): Likewise. (make-displayspec-from-type-and-options): Likewise. (update-displayspec-from-optspec-and-value): Likewise. (db-setup-data-display-buffer): Likewise. (db-make-data-display-buffer): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. (db-additional-data-display-buffer): Likewise. (db-change-format): Likewise. (db-emergency-restore-format): Likewise. (display-record): Likewise. (displayspec->printed-rep): Likewise. (displayspec->displayed-rep): Likewise. 2004-09-02 Thien-Thi Nguyen * db-interfa.el (db-field-help): Locals name munging; nfc. (db-set-field-help): Likewise. (db-kill-buffers): Likewise. (db-bury): Likewise. (db-save-some-databases): Likewise. (db-find-file): Likewise. (db-find-read-in-database): Likewise. (database-clean-data-display-buffers): Likewise. (db-revert-database): Likewise. (dbc-set-index): Likewise. (db-select-record): Likewise. (db-previous-screen-or-record): Likewise. (db-add-record): Likewise. (db-output-record-to-db): Likewise. (db-field-query-replace): Likewise. (db-search-field): Likewise. (db-report): Likewise. (data-display-buffer-database): Likewise. 2004-09-01 Thien-Thi Nguyen * db-rep.el (database-unnamed-p): Delete defsubst. * db-interfa.el (db-save-database-helper): Incorporate `database-unnamed-p'. 2004-09-01 Thien-Thi Nguyen * db-rep.el (database-normalize-index): Delete defsubst. (next-link-and-index): Incorporate `database-normalize-index'. 2004-09-01 Thien-Thi Nguyen * db-rep.el (database-index-in-range): Delete defsubst. * db-interfa.el (db-select-record): Incorporate `database-index-in-range'. 2004-09-01 Thien-Thi Nguyen * db-rep.el (make-default-record): Delete func. * db-interfa.el (db-add-record): Incorporate `make-default-record'. 2004-09-01 Thien-Thi Nguyen * db-rep.el (database-delete-link): Delete func. * db-interfa.el (db-delete-record): Incorporate `database-delete-link'. 2004-09-01 Thien-Thi Nguyen * db-rep.el (database-delete-record-at-index): Delete unused func. 2004-08-29 Thien-Thi Nguyen * configure.ac (VERSION): Bump to "1.23" for release. 2004-08-29 Thien-Thi Nguyen * Makefile.in (distfiles): Add def.survey, def-indexed.surevey and def-undoc.survey. (dist): Fix bugs: Make subdir $(dd)/skram. Also, explicitly specify output filename for cp(1). 2004-08-29 Thien-Thi Nguyen * Makefile.in (cvs-state-summary): New target. 2004-08-29 Thien-Thi Nguyen * db-interfa.el (database-view-mode-map): Split decl and init. (database-edit-mode-map): Likewise. * db-sort.el (database-sort-mode-map): Likewise. * db-summary.el (database-summary-mode-map): Likewise. 2004-08-29 Thien-Thi Nguyen * db-format.el (dbf-set-summary-format): Use `read-string' to query for new value. Insert old value to allow editing. 2004-08-29 Thien-Thi Nguyen * db-file-io.el (db-default-field-type): Delete deflocalvar. * db-rep.el (database-set-fieldnames-to-list): Take optional third arg. Prefer it over `db-default-field-type'. Add binding check for `db-default-field-type'. Use `string' as last resort. * db-tagged.el (db-tagged-setup-internal): No longer set `db-default-field-type'. Instead pass default recordfieldspecs to `database-set-fieldnames-to-list'. * db-rdb.el (db-rdb-setup-internal): Likewise. * edb.texi (Per-data-display-buffer variables): Gut. (The database structure): Rewrite `database-set-fieldnames-to-list' docs. Explain deprecation of `db-default-field-type' and migration path. Add 3d arg to `database-set-fieldnames-to-list' in example. 2004-08-29 Thien-Thi Nguyen * db-file-io.el (db-set-fieldname-vars): Delete func. * db-rep.el (database-set-fieldnames-to-list): Incorporate `db-set-fieldname-vars'. 2004-08-29 Thien-Thi Nguyen * db-convert.el (db-convert): Use `database-set-fieldnames-to-list' directly, clearing the database `fieldnames' slot first. 2004-08-28 Thien-Thi Nguyen * db-format.el (database-buffer-p): Delete func. * db-file-io.el (write-database-file): Use `db-data-display-buffer-p' and `db-summary-buffer-p' directly. 2004-08-28 Thien-Thi Nguyen * skram/GNUmakefile: Add copyright notice. (emacs): New var. (all): New target. (wily-emacs): New var. (sk2): New target. (sk3): Likewise. (clean): Delete sk2 and sk3, but not skram.data. (realclean): New target. 2004-08-28 Thien-Thi Nguyen * database.el (edb-essential-file-names): Add "db-nosetf". (edb-required-file-names): Remove "db-nosetf". 2004-08-28 Thien-Thi Nguyen * Makefile.in (EL-FILES): Add db-nosetf.el. (ELC-FILES): Add db-nosetf.elc. 2004-08-28 Thien-Thi Nguyen * database.el (edb-required-file-names): Add "db-nosetf". (edb-autoloaded-file-names): Remove "db-nosetf". 2004-08-28 Thien-Thi Nguyen * skram: New subdir. * skram/README: New file. * skram/GNUmakefile: Likewise. * skram/skram.fmt: Likewise. * Makefile.in (distfiles): Add some files in subdir `skram'. 2004-08-28 Thien-Thi Nguyen * Makefile.in (all): Symlink /etc/passwd in examples. (dist): Do not distribute examples/passwd. 2004-08-28 Thien-Thi Nguyen * db-util.el (db-copy-buffer-local-variables): Rewrite. Handle `enable-multibyte-characters' specially. 2004-08-28 Thien-Thi Nguyen * db-file-io.el: Require `pp'. (write-database-file): Use `pp' instead of `print'. 2004-08-28 Thien-Thi Nguyen * db-interfa.el (dbc-compute-index): Delete func. (dbf-finished-sorting): Inline `dbc-compute-index'. 2004-08-28 Thien-Thi Nguyen * db-interfa.el: Remove disabled `db-search' implementation. 2004-08-28 Thien-Thi Nguyen * db-summary.el (dbs-insert-link-summary): Rewrite. (make-summary-initial-indentation): Delete unused func. (make-summary-indentation): Likewise. 2004-08-28 Thien-Thi Nguyen * db-rep.el (record->link-and-index): Delete unused func. 2004-08-28 Thien-Thi Nguyen * db-rep.el (database-list-of-links): Delete func. * db-sort.el (database-sort): Use `maplinks' to get list of links. 2004-08-28 Thien-Thi Nguyen * db-format.el (db-next-field-internal): Fix bug introduced 2004-06-02 during one-armed-if transform. 2004-08-28 Thien-Thi Nguyen * db-util.el (db-in-buffer): Rename from `in-buffer'. * database.el (db-log): Use new name. * db-file-io.el (read-database-file): Likewise. (write-database-file): Likewise. * db-format.el (db-setup-data-display-buffer): Likewise. * db-interfa.el (db-save-some-databases): Likewise. (db-find-file): Likewise. (data-display-buffer-database): Likewise. * db-sort.el (dbsi-use-ordering-make-database-default): Likewise. (dbsi-use-ordering-make-buffer-default): Likewise. * db-summary.el (dbf-in-summary-buffer): Likewise. (dbs-in-data-display-buffer): Likewise. (db-in-data-display-buffer): Likewise. (db-summary): Likewise. (db-create-summary-buffer): Likewise. (dbs-synch-format-with-summary): Likewise. * db-two-dbs.el (db-merge): Likewise. (db-merge-records): Likewise. (database-compare-hack): Likewise. 2004-08-28 Thien-Thi Nguyen * db-util.el (db-buffer-substitute): Rename from `buffer-substitute'. * db-file-io.el (database-perform-substitutions): Use new name. 2004-08-27 Thien-Thi Nguyen * db-interfa.el: Fix bug: For keybindings in both keymaps, use &optional instead of &rest in formals. 2004-08-27 Thien-Thi Nguyen * db-rep.el (database-full-recordsep-string): Locals name munging; nfc. (recordfieldspecs-compatible): Likewise. (database-recordfieldspec): Likewise. (database-set-recordfieldspec): Likewise. (database-recordfieldspec-type): Likewise. (record-field): Likewise. (record-check-constraint): Likewise. (record-set-field): Likewise. (read-sep-items): Likewise. (write-sep-items): Likewise. (next-link-and-index): Likewise. (database-add-record): Likewise. (make-default-record): Likewise. (database-delete-record-at-index): Likewise. (maplinks): Likewise. (maprecords): Likewise. (print-database): Likewise. (print-record): Likewise. (print-compare-records): Likewise. 2004-08-27 Thien-Thi Nguyen * db-file-io.el: Throughout, update `kill-buffer' call. * db-interfa.el: Likewise. * db-sort.el: Likewise. 2004-08-27 Thien-Thi Nguyen * edb.texi (The link structure): Mention `link-set-record-slot' lack. 2004-08-27 Thien-Thi Nguyen * db-rep.el (database-last-link): Delete defsubst. (next-link-and-index): Inline `database-last-link'. 2004-08-27 Thien-Thi Nguyen * db-interfa.el (db-toggle-internal-file-layout): Display informative message after toggling. 2004-08-27 Thien-Thi Nguyen * db-interfa.el: Use a table to construct keymaps. * db-sort.el: Likewise * db-summary.el: Likewise. 2004-08-27 Thien-Thi Nguyen * db-format.el (db-setup-data-display-buffer): Use `crypt-insert-file-contents' if available, otherwise `insert-file-contents'. * db-util.el (db-insert-file-contents): Delete func. 2004-08-27 Thien-Thi Nguyen * db-format.el (dbf-displayspec-begin-markers): Delete unused var. 2004-08-27 Thien-Thi Nguyen * db-format.el (indentify-absolute): Delete func. (insert): No longer fset this to `db-old-insert'. (db-old-insert): Delete alias for pre-fset `insert'. Update callers to use `insert' directly. (db-insert-item): Delete func. (db-insert): Likewise. 2004-08-27 Thien-Thi Nguyen * database.el (db-logged): Delete undocumented var. (db-log): No longer set `db-logged'. 2004-08-27 Thien-Thi Nguyen * db-nosetf.el: New file. * database.el (edb-autoloaded-file-names): Add "db-nosetf". * db-file-io.el: Throughout, use setf-style setters. (sepinfo-set-regexp-and-submatch-from-string): Rewrite to accept rx-setf and subrx-setf args. Update callers. * db-format.el: Throughout, use setf-style setters. Move setter defsubst forms to db-nosetf.el. * db-rep.el: Likewise. * db-interfa.el: Throughout, use setf-style setters. * db-isbn.el: Likewise. * db-rdb.el: Likewise. * db-sort.el: Likewise. * db-summary.el: Likewise. * db-tagged.el: Likewise. * db-time.el: Likewise. * db-two-dbs.el: Likewise. * db-types.el: Likewise. 2004-08-26 Thien-Thi Nguyen * db-summary.el (dbf-update-summary-item): Use `next-link-and-index'. 2004-08-26 Thien-Thi Nguyen * db-time.el (format-date): Fix bug: Use `format' since newer versions of `concat' don't accept numbers. 2004-08-26 Thien-Thi Nguyen * db-rep.el (database-link): Delete defsubst. (database-link-and-index): Likewise. (database-add-record): Call `next-link-and-index' directly. 2004-08-26 Thien-Thi Nguyen * db-util.el (db-vararg-call): Fix typo. * db-interfa.el (dbf-previous-screen-or-record): Likewise. 2004-08-26 Thien-Thi Nguyen * database.el: Comment munging; nfc. * db-file-io.el: Likewise. * db-format.el: Likewise. * db-interfa.el: Likewise. * db-rep.el: Likewise. * db-sort.el: Likewise. * db-summary.el: Likewise. * db-two-dbs.el: Likewise. * db-types.el: Likewise. * db-util.el: Likewise. 2004-08-25 Thien-Thi Nguyen * db-util.el (eob-visible-p): Delete func. (bob-visible-p): Likewise. * db-interfa.el (dbf-next-screen-or-record): Use `window-end' and `point-max'. (dbf-previous-screen-or-record): Use `window-start' and `point-min'. 2004-08-25 Thien-Thi Nguyen * db-util.el (db-symbol-append): Delete unused func. 2004-08-25 Thien-Thi Nguyen * db-util.el (db-count-array): Rename from `count-array'. * db-format.el (displayspec->printed-rep): Use `db-count-array'. * db-summary (format->lines-and-stringform-list): Likewise. 2004-08-25 Thien-Thi Nguyen * db-util.el (db-vararg-call): Use `nthcdr' and `dotimes'. Also, use `format' instead of `concat' + `int-to-string'. (count-array): Use `dotimes'. 2004-08-25 Thien-Thi Nguyen * db-rep.el (copy-record-to-record): Use `dotimes'. (make-default-record): Likewise. (print-record): Likewise. (print-compare-records): Likewise. 2004-08-25 Thien-Thi Nguyen * db-rep.el (recordfieldspec-sort-function): Merge `order->sort'. (order->sort): Delete func. (recordfieldspec-order-function): Merge `sort->order'. (sort->order): Delete func. 2004-08-25 Thien-Thi Nguyen * db-rep.el (database-full-fieldsep-string): Elide local; nfc. 2004-08-25 Thien-Thi Nguyen * db-rep.el (database-set-modified-p-internal): Delete unused func. (database-set-modified-p): Elide local; nfc. 2004-08-25 Thien-Thi Nguyen * db-rep.el (database): For defstruct slot `print-name', use `format' instead of `concat'. 2004-08-25 Thien-Thi Nguyen * db-rep.el (maprecords-macro): Fix syntax bug: For form `declare' sub-form `debug', make cdr a single list. * db-sort.el (with-orderer): Likewise. (with-sorter): Likewise. * db-util.el (in-buffer): Likewise. (db-funcall-maybe-default): Remove superfluous `declare' form. 2004-08-25 Thien-Thi Nguyen * db-interfa.el (db-old-save-some-buffers): Delete fset. (save-some-buffers): No longer fset. (db-save-some-buffers): Call `save-some-buffers' directly. * edb.texi (Database mode): Update info on `db-save-some-buffers' and `save-some-buffers'. (Exiting Emacs or saving files): Likewise. 2004-08-25 Thien-Thi Nguyen * db-format.el (make-optspecinfo): Delete macro. (optspec-list): Map lambda directly on init. 2004-08-25 Thien-Thi Nguyen * database.el: Use `incf' and `decf'. * db-convert.el: Likewise. * db-file-io.el: Likewise. * db-format.el: Likewise. * db-interfa.el: Likewise. * db-rdb.el: Likewise. * db-rep.el: Likewise. * db-summary.el: Likewise. * db-time.el: Likewise. * db-two-dbs.el: Likewise. * db-util.el: Likewise. 2004-08-25 Thien-Thi Nguyen * database.el (edb-update): Delete command. 2004-08-25 Thien-Thi Nguyen * edb.texi (Updates to EDB): Bifurcate pre- and post-1.22. 2004-08-25 Thien-Thi Nguyen * database.el: Require `cl' when compiling. (byte-compile-database): Use `dolist'. * db-convert.el (db-convert-record): Likewise. * db-file-io.el (database-set-links-from-list): Likewise. (database-stored->actual-internal): Likewise. * db-format.el (make-optspecinfo): Likewise. * db-interfa.el (db-save-some-databases): Likewise. (database-clean-data-display-buffers): Likewise. * db-isbntst.el (check-isbns): Likewise. * db-rdb.el (db-rdb-lookup-field): Likewise. * db-rep.el (map-data-display-buffers): Likewise. * db-tagged.el (lookup-field): Likewise. * db-time.el (test-date-formats): Likewise. (test-time-parser): Likewise. * db-types.el (db-enum-process-alternatives): Likewise. * db-util.el (buffer-substitute): Likewise. 2004-08-24 Thien-Thi Nguyen * Makefile.in (hacksup.el): For macros, look in `declare' forms for lisp-indent-hook info. 2004-08-24 Thien-Thi Nguyen * database.el (db-debug): Convert attendant indentation and edebug `put' forms into a single `declare' form in the body. (db-debug-message): Likewise. * db-file-io.el (database-set-links-from-list): Likewise. * db-format.el (dbf-always): Likewise. * db-interfa.el (dbf-goto-record-internal): Likewise. * db-rep.el (maplinks-macro): Likewise. (maprecords-macro): Likewise. * db-sort.el (with-orderer): Likewise. (with-sorter): Likewise. (with-pc): Likewise. (with-pc-and-ti): Likewise. * db-summary.el (dbf-in-summary-buffer): Likewise. (dbs-in-data-display-buffer): Likewise. (db-in-data-display-buffer): Likewise. * db-util.el (deflocalvar): Likewise. (db-funcall-maybe): Likewise. (in-buffer): Likewise. 2004-08-21 Thien-Thi Nguyen * database.el: Throughout, use `single-quote foo' instead of `(function foo)'. Also use `mapc' where appropriate. * db-convert.el: Likewise. * db-file-io.el: Likewise. * db-format.el: Likewise. * db-interfa.el: Likewise. * db-rdb.el: Likewise. * db-rep.el: Likewise. * db-sort.el: Likewise. * db-tagged.el: Likewise. * db-time.el: Likewise. * db-types.el: Likewise. * db-util.el: Likewise. 2004-08-21 Thien-Thi Nguyen * Makefile.in (hacksup.el): Use `mapc'. 2004-08-21 Thien-Thi Nguyen * Makefile.in (clean): Also delete *.survey files. (surveys): New target. (def-undoc.survey): Likewise. (info-stdout): New var. (def-indexed.survey): New target. (def.survey): Likewise. 2004-08-20 Thien-Thi Nguyen * db-util.el (db-file-resolve-symlink): Delete func. (db-same-file-p): Use `file-chase-links'. 2004-08-20 Thien-Thi Nguyen * db-util.el (db-functionp): Delete subst. * db-sort.el (database-sort): Use `functionp'. (db-make-ordering-fields-canonical): Likewise. * db-format.el (make-optspecinfo): Likewise. 2004-08-20 Thien-Thi Nguyen * db-util.el (in-buffer-simple): Delete macro and attendant `put' form. (db-copy-buffer-local-variables): Use `with-current-buffer'. * db-rep.el (database-set-modified-p): Use `with-current-buffer'. * database.el (byte-compile-database): Likewise. 2004-08-20 Thien-Thi Nguyen * db-util.el (in-window): Delete macro and attendant `put' forms. * db-interfa.el (db-next-screen-or-record): Use `with-selected-window'. (db-previous-screen-or-record): Likewise. 2004-08-20 Thien-Thi Nguyen * db-util.el (db-match-string): Delete func. (db-match-string-maybe): Likewise. (db-string-trim-whitespace): Use `match-string'. * db-format.el (db-next-field-internal): Use `string-match'. (db-previous-field-internal): Likewise. (make-displayspec-from-string): Likewise. (make-displayspec-from-string-internal): Likewise. (make-displayspec-from-type-and-options): Likewise. (db-setup-ddb-parse-displayspecs): Likewise. * db-rdb.el (db-rdb-list-rrfr): Use `match-string'. (db-rdb-read-list-field-defs): Likewise. * db-summary.el (format->lines-and-stringform-list): Use `match-string' in comment; nfc. * db-tagged.el (db-tagged-rrfr): Use `match-string'. * db-time.el (parse-date-string): Use `match-string'. (parse-time-string): Likewise. * edb.texi (Nonregular database example): Use `match-string' in example code. 2004-07-24 Thien-Thi Nguyen * db-util.el (db-vararg-call): No longer use `subseq'; do it "manually". 2004-07-24 Thien-Thi Nguyen * db-util.el (db-symbol-append): Rename from `symbol-append'. * db-format.el (make-optspecinfo): Use `db-symbol-append'. 2004-07-24 Thien-Thi Nguyen * db-util.el (db-string-replace-regexp-2): Rename from `string-replace-regexp-2'. Update caller. 2004-07-24 Thien-Thi Nguyen * db-util.el (db-rassoc): Delete func. * db-types.el (db-enum-make-stored->actual): Use `rassoc' builtin. (abbreviate-state): Likewise. 2004-07-24 Thien-Thi Nguyen * db-util.el (firstn): Delete func. (db-vararg-call): Use `subseq' instead of `firstn'. 2004-07-24 Thien-Thi Nguyen * edb.texi (EDB support): Update mailing list info. (Updates to EDB): Likewise. (Reporting bugs): Update email addr for bug reports. 2004-07-24 Thien-Thi Nguyen * edb.texi: Spacing changes; nfc. 2004-07-24 Thien-Thi Nguyen * edb.texi (Display specification optional parameters): Typofix. 2004-06-09 Thien-Thi Nguyen * Makefile.in (installcheck): Use $(RM). 2004-06-06 Thien-Thi Nguyen * edb.texi: Remove superfluous @noindent. Use @lisp instead of @example where appropriate. Refill some lisp examples. Make sure there is an empty line before/after each example. 2004-06-05 Thien-Thi Nguyen * edb.texi (Introduction): Use "some other database systems". 2004-06-02 Thien-Thi Nguyen * configure.ac (VERSION): Bump to "1.22" for release. 2004-06-02 Thien-Thi Nguyen * Makefile.in (distfiles): Add HACKING. 2004-06-02 Thien-Thi Nguyen * configure.ac: Fix bug: Use package name as first arg to AC_INIT. 2004-06-02 Thien-Thi Nguyen * Makefile.in (edb.info): Also depend on version.texi. (version.texi): New target. (distfiles): Add version.texi. * edb.texi: Set @paragraphindent in header. Include version.texi. Update copyright. Replace hard-coded values w/ those from version.texi. For all menu items, remove redundant blurbs. For all @node lines, remove next, prev and parent node names. Use @c instead of @comment. (Top): Intersperse headers in menu. Use @detailmenu. (Installing EDB): Add subsection "EDB 1.22 and Later". (Compiling EDB): Mention non-relevance of text. 2004-06-02 Thien-Thi Nguyen * NEWS: New file. * Makefile.in (distfiles): Add NEWS. 2004-06-02 Thien-Thi Nguyen * db-util.el: Re-indent. Replace `? ' or `?\ ' with 32. Convert one-armed `if' forms to `when' or `unless'. Eliminate superfluous `progn' in `if' else-clause. Convert quote, quasiquote, unquote and unquote-splicing syntax from functional construct (with parens) to terse (without). Remove `function' and `quote' from around `lambda' form. * db-types.el, db-two-dbs.el, db-time.el, db-tagged.el, db-summary.el, db-sort.el, db-search.el, db-rep.el, db-rdb.el, db-isbntst.el, db-isbn.el, db-interfa.el, db-format.el, db-file-io.el, db-convert.el, database.el: Likewise. 2004-06-01 Thien-Thi Nguyen * Makefile.in (hacksup.el): Depend on $(EL-FILES). Add indentation setup for "database-set-*" symbols. 2004-06-01 Thien-Thi Nguyen * Makefile.in (hacksup.el): New target. (distfiles): Add hacksup.el. 2004-05-31 Thien-Thi Nguyen * Makefile.in (check): New target. 2004-05-17 Thien-Thi Nguyen * Makefile.in (distfiles): Add `examples'. (dist): Pass "-R" to cp(1). Remove CVS subdirs and .cvsignore files. Fix omission bug: Pass "-h" to tar(1). 2004-05-17 Thien-Thi Nguyen * database.el: Move summary of distribution terms before Commentary. Use "EDB" directly instead of making analogy to GNU Emacs. * db-convert.el: Add explicit copyright notice. Add summary of distribution terms. Remove "Keywords" comment. * db-file-io.el, db-format.el, db-interfa.el, db-isbn.el, db-isbntst.el, db-rdb.el, db-rep.el, db-search.el, db-sort.el, db-summary.el, db-tagged.el, db-time.el, db-two-dbs.el, db-types.el, db-util.el: Likewise. 2004-05-17 Thien-Thi Nguyen * Makefile.in (dist): Delete $(dd)/database.el before doing the sed. 2004-05-17 Thien-Thi Nguyen * autogen.sh (amfiles): New var. Use it for symlinking. * Makefile.in (distfiles): Add COPYING and INSTALL. 2004-05-17 Thien-Thi Nguyen * database.el: Update copyright. Remove LCD archive entry from Commentary. Throughout, replace hardcoded EDB version and release-date info with `@EDB-VERSION@' and `@EDB-DATE@', respectively. * Makefile.in (srcdir, top_srcdir): New vars. (mkinstalldirs): Use $(top_srcdir). (distfiles, dd): New vars. (dist): New target. 2004-05-17 Thien-Thi Nguyen * configure.ac: No longer probe $(EMACS) for default `sitelisp' value. Instead, hardcode it to be `$datadir/emacs/site-lisp'. * Makefile.in (sitelisp): Substitute @sitelisp@ directly. 2004-05-17 Thien-Thi Nguyen * db-interfa.el (db-set-auto-edit-mode): Throw error if called. (db-field-query-replace): Fix bug: Use three placeholders in format string, corresponding to the args to be formatted. 2004-05-17 Thien-Thi Nguyen * db-convert.el (db-canonicalize-creation-method): Fix call to `fieldname->fieldnumber'. 2004-05-17 Thien-Thi Nguyen * db-time.el (format-date-ddmmyy-separator): Use `defvar', not `defconst'. (format-date-ddmmmyy-separator): Likewise. 2004-05-17 Thien-Thi Nguyen * Makefile.in (installcheck): No longer change directories. Instead, find default `load-path', prefix it with $(sitelisp) and use the result with prefix-style env var `EMACSLOADPATH' for $(EMACS) invocation. (clean): No longer delete $(INFO-FILES). (maintainerclean): New target. 2004-05-16 Thien-Thi Nguyen * Makefile.in (installcheck): New target. 2004-05-16 Thien-Thi Nguyen * Makefile.in (install): Use $(INSTALL_DATA) for info files. (clean): No longer delete defunct BYTE-COMPILE.el. 2004-05-16 Thien-Thi Nguyen * Makefile.in: Update copyright. Rewrite. 2004-05-15 Thien-Thi Nguyen * configure.ac: Add check for emacs; raise error if not found. Add check for emacs site-lisp dir, including override capability using configure option `--with-sitelisp'. 2004-05-15 Thien-Thi Nguyen * autogen.sh: New file. 2004-05-15 Thien-Thi Nguyen * configure.ac: New file. 2004-05-15 Thien-Thi Nguyen * ANONCVS, AUTHORS: New files. 2004-05-15 Thien-Thi Nguyen * Makefile.in: Initial checkin from Michael Ernst. * db-format.el, db-rdb.el, db-summary.el, db-types.el, database.el, db-interfa.el, db-rep.el, db-tagged.el, db-util.el, db-convert.el, db-isbn.el, db-search.el, db-time.el, edb.texi, db-file-io.el, db-isbntst.el, db-sort.el, db-two-dbs.el, README: Likewise. * examples: New dir. Local variables: coding: utf-8 End: edb-1.31/GNUmakefile.in0000444000175000017500000000644611005407534013052 0ustar ttnttn# GNUmakefile for EDB. # Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen # # This file is part of EDB. # # EDB 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 3, or (at your option) any later # version. # # EDB 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 EDB; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. ########################################################################### # Type "make" to byte-compile EDB and create Info files. # You must run this from the directory containing the EDB files. # Optional arguments to make: # all (same as no argument) make .elc and .info files # install copy edb.info to $(infodir), .el{c} files to $(sitelisp)/edb # clean remove all .elc and generated .el files # tags create TAGS file # dist (for maintainer) make distribution tarball ########################################################################### ### Variables ### srcdir = @srcdir@ top_srcdir = @top_srcdir@ prefix = @prefix@ datarootdir = @datarootdir@ datadir = @datadir@ infodir = @infodir@ sitelisp = @sitelisp@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ mkinstalldirs = $(top_srcdir)/install-sh -d EDB-VERSION = @PACKAGE_VERSION@ ETAGS = etags RM = rm -f ### ### Users shouldn't have to modify anything below this line. ### INFO-FILES = doc/edb.info* ########################################################################### ### Rules ### recursive-%: for sub in doc lisp ; do $(MAKE) -C $$sub $* ; done all: recursive-all check: cd tests && $(MAKE) $@ install: recursive-install installcheck: recursive-installcheck clean: recursive-clean cd skram && $(MAKE) $@ maintainerclean: clean tags: TAGS TAGS: $(source-el-files) $(ETAGS) $^ cvs-state-summary: ttn-do display-cvs-state-summary lisp . examples skram ########################################################################### ### Distribution ### dd = edb-$(EDB-VERSION) extradist = configure install-sh \ doc/edb.info \ doc/refcard.ps \ doc/refcard.version.tex \ doc/texinfo.tex \ doc/version.texi minusdist = .gitignore autogen.sh rw-ok = \ $(addprefix examples/, \ arb-demo arb-demo-regexp btxdb/examples/bibtex.bib tepdb \ www-links www-links2 www-links3) \ $(patsubst %, examples/%.dat, \ eicsw forms-demo2-int forms-demo2 geneal names rolo-jik btxdb/journals) \ $(patsubst %, examples/%.edb, \ forms-demo2-inherent) dist: @test -d .git || { echo ERROR: No .git subdir. ; false ; } rm -rf $(dd) $(dd).tar.gz mkdir $(dd) cp -p --parents $(wildcard $(extradist)) \ $(shell git ls-files $(addprefix -x , $(wildcard $(minusdist)))) \ $(dd) sed -e 's/@''EDB-VERSION''@/$(EDB-VERSION)/g' \ -e 's/@''EDB-DATE''@/'`date +%Y-%m-%d`'/g' \ -i $(dd)/lisp/database.el cd $(dd) && chmod +w $(strip $(rw-ok)) GZIP=--best tar czhf $(dd).tar.gz $(dd) $(RM) -r $(dd) # GNUmakefile.in ends here edb-1.31/HACKING0000444000175000017500000000257110747566354011377 0ustar ttnttn-*-outline-*- * hacksup.el When editing the elisp, first load hacksup.el to set up indentation, otherwise the code will tend to unceremoniously crawl off the right side of the screen. * DEBUG=1 Normally, tests/ebatch.in (used by "make check") discards output. However, if you set env var DEBUG, it enables stdout and stderr. * Patches For small changes, please include a suitable ChangeLog entry of the form: YYYY-MM-DD J. Random Hacker (tiny change) * FILE.el (func-1): Fix foo handling. (func-2): Take additional arg quux, baaz. Update callers. (func-3): Likewise. (var-1): Doc fix. The precise date is not important; it will be adjusted when the patch is installed. This example is also slightly suboptimal in that there are many different changes included together (for the sake of demonstration). It is better to instead separate each change to its own patch + ChangeLog entry. To make the patch, use "diff -u" against either a fresh cvs checkout (best), or the latest release (next best). Patches against older releases will be considered at lower priority, if at all. * public repository To get a source tree: $ git clone http://www.gnuvola.org/wip/edb.git Once you have a source tree: $ sh autogen.sh See autogen.sh comments for which tool versions are recommended to install on your system (minimally -- probably later versions work, too). edb-1.31/NEWS0000444000175000017500000007351411016451222011065 0ustar ttnttnNEWS for EDB, the Emacs Database Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen See the end for copying conditions. - 1.31 | 2008-05-26 - Install fix: install edb.info, too! - 1.30 | 2008-05-26 - Build fix: "gmake all" now works under Windoze No pipes there, how peculiar (BUGS #15). - Bugfix: Deleting a record no longer signals `args-out-of-range' Previously, for non-inherent databases, 9% of the deletions (1/11) would result in a `args-out-of-range' error, and possibly corrupt the database (BUGS #16). - Changes to Database Edit commands - `C-a' twice goes to beginning of field - `C-e' twice goes to end of field That is, on the first invocation, the commands behave normally, going to beginning or end of line, respectively. A successive invocation goes "further". This is useful for multi-line fields, since `M-<' and `M->' are by default coopted for `db-first-record' and `db-last-record', respectively. - `C-k' respects `kill-whole-line' - New handling for file-not-writable on interactive save On save, where `noninteractive' is nil, if file is not writable, offer to make it writable and continue. This uses `y-or-n-p' to query and does a simple `set-file-modes' (no vc integration). - 1.29 | 2008-01-17 - License now GPLv3+ (see COPYING) - Bugfix: Single-field records no longer trigger warning on read Previously, a database with only a single field per record would trigger some warning messages and eventually query the user: "Bad file format; try reading anyway?". Answering "yes" would successfully read in the data (anyway). Now, such databases are read normally (w/o incident). - Bugfix: Pre- and post- regexp-specified cruft no longer discarded Previously, if a database's pre-first-regexp was specified, the text matching that regexp (on read) was discarded (on write). Likewise for post-last-regexp. This text is now saved and later used on write. With this bugfix, BUGS.edb is finally able to both read and write the BUGS file (bug #1 resolved). Good-bye ostrich dayz! - Emacs no longer asks about some hooks as file local variable Specifying `db-before-read-hooks' and `db-after-read-hooks' in a format file's Local Variables block makes some versions of Emacs ask about whether or not the value is "safe". EDB now arranges for Emacs to consider values that satisfy `edb-hookp' to be safe (thus avoiding this particular interruption). - Command edb-1int-to-single autoloaded This command -- see (info "(edb) edb-1int-to-single") -- can now be invoked with M-x, once EDB is loaded. - Control files can specify a "schema basis" This is a variable that holds a plist of control properties, useful for sharing common properties among many databases. The values therein undergo elaboration just like normal control props prior to the normal control props. For example, in ~/.emacs: (defvar foo (list :fields [a b c] :record-defaults 'foo-new-record-plist)) In x.edb: :EDB (single foo) :name "x foo!" In y.edb: :EDB (single foo) :name "y foo!" In z.edb: :EDB (single foo) :name "z foo!" :record-defaults 'foo-z-new-record-plist ;; override See (info "(edb) Specifying control") for details. - Command extended: db-add-record can now append This command now accepts an optional arg APPEND. If non-nil, add the new record after the last record in the database and display "Appended" instead of "Inserted". - 1.28 | 2007-05-29 - Bugfix: C-h m (describe-mode) no longer throws error Previously, `C-h m' in either Database View or Database Edit mode would throw a "Symbol's function definition is void" error. This bug was introduced in EDB 1.26. - Bugfix: displayspec can handle multiple options Previously, the displayspec `\id,width=5,right-justify' would render the field `id' without any padding whatsoever. This was due to a bug in `right-justify' handling as well as a more general (regexp-related -- surprise, surprise) problem handling multiple options. These are now fixed. - Dropped items announced in EDB 1.27 NEWS (see below) - Support for FOO-separator variables in edb-t-timedate1.el - Six functions (internal) database-recordfieldspec (internal) database-recordfieldspec-type (internal) database-set-recordfieldspec (spurious) db-tagged-rrfr-hooks (spurious) db-tagged-wrfr-before-hooks (spurious) db-tagged-wrfr-after-hooks - Control file can start w/ comments and blank lines The text ":EDB " used to be expected at the very beginning of the buffer; now, any preceding comment and blank lines are skipped w/o error. See examples/null.edb for an example. - New Database Summary mode keybinding: `S' now runs `db-sort' - New documentation: refcard Erich Wälde contributed refcard.tex (source for refcard.ps), in the doc/ subdir. - New command: edb-interact Actually, this is just `edb-EXPERIMENTAL-interact' renamed; the old name is a now an alias, to be removed for EDB 1.29. - Maintenance uses GNU Autoconf 2.60 - 1.27 | 2006-07-13 - Configuration bugfix: Emacs executable specification made consistent Configuration and build have different methods for specifying the Emacs executable -- these used to be not easily overridden. Now you can override them in both contexts similarly, by specifying the environment variable `EMACS'. See README. - Installation bugfix: Remember to install all relevant files! Some files (db-lemacs.el, db-nosetf.el and db-oldnames.el) are now installed (and not just distributed). This error was due to a regression in the makefile introduced in EDB 1.26. - Bugfix: Substitutions use literal text for replacement Some i/o operations temporarily replace difficult-to-manage text (like backslashes) w/ an easier-to-manage string. These used to use `replace-match' without specifying that the replacement be literal, which caused an "Invalid use of `\\' in replacement text" error in some cases. These have been fixed. - Bugfixes for edb-t-timedate.el - `edb-t-timedate1:format-date' renders "%yy" correctly This used to render years as modulo 1900, resulting in more than two characters, for year 2000 and later. For example: (defun (demo Y M D) (let ((date (edb-t-timedate1:make-date Y M D))) (edb-t-timedate1:format-date "%yy" date))) before: (demo 2006 5 31) => "106" now: (demo 2006 5 31) => "06" - Specialized formatting functions use format consistent w/ name Certain functions edb-t-timedate1:format-date-FOO used to use formatting codes inconsistent w/ their names. Here is a table showing the change and an example for each FOO, using SPC as a separator between components (actual default separators vary): FOO before (example) now (example) ddmmyy %d %m %yy "3 5 06" %dd %mm %yy "03 05 06" ddmmmyy %d %mon %yy "3 May 06" %dd %mon %yy "03 May 06" yyyymmdd %year %m %d "2006 5 3" %year %mm %dd "2006 05 03" - Bugfix: Last record no longer ignored for "inherent data" For controls with inherent data (specified with the `:data' control property), EDB used to silently ignore the last record (off-by-one error in the implementation). Now, all records are read properly. Also, the order of the records in memory is now maintained to be the same as the order in the control. - Bugfix: Emacs no longer queries about "safe" local variables Previously, `edb-EXPERIMENTAL-interact' used to cause Emacs 22 to query about whether or not certain file-local variables are "safe". Now, these internal details are properly hidden. - Bugfix: Database w/ inherent data can coexist w/ other databases Previously, a control file w/ inherent data could not be read in the presence of other databases due to a bug in the accounting internals; EDB would throw an error (wrong-type-arg: stringp). Now, these databases can coexist w/o this particular problem. For example: (require 'database) (dired "examples") (edb-EXPERIMENTAL-interact "arb-demo.edb" "arb-demo") (edb-EXPERIMENTAL-interact "forms-demo2-inherent.edb" nil) - Emacs 21.x compatibility fixes - No longer use three args with `defalias' - Define `insert-buffer-substring-no-properties' if necessary - Dropped items - Command: db-convert This was once documented in the info page as "rudimentary", but was otherwise unreferenced and unused both in EDB and elsewhere. Similar functionality may return in the future, after some of EDB 1.x's (excessive) dynamicism is properly reigned in. - Macro: deflocalvar - Function: define-displaytype-from-optstring - Function: define-one-char-enum-displaytype - Function: define-type-alias These were either unused, unimplemented (and throwing error if called), or made obsolete by internal changes. - Coordination with crypt++.el EDB no longer calls `crypt-insert-file-contents' from external package crypt++.el (if loaded). Instead, you can enable Auto Compression mode, which is included with Emacs. - Items listed in advance notice from EDB 1.26 NEWS (see below) - Backward-incompatible change: format of :locals control more concise Previously, the :locals vector elements could be either a symbol or a pair (SYMBOL . INIT-VAL). Now, the format for the latter variant is (SYMBOL INIT-FORM). Also, INIT-FORM is now evaluated so you don't need to do that yourself. For example: before: :locals `[foo (ht . ,(make-hash-table)) bar] now: :locals [foo (ht (make-hash-table)) bar] In other words, the syntax resembles that of a `let' bindings block with square braces instead of parentheses on the outside. - Example databases writable The sooner you play with EDB (once it is built and loaded), the sooner you can report any bugs you find. (Thanks!) - Mode lines say "Database" as part of the mode name before: -***-Database: machine-dbase (Edit Abbrev 42/431)---All- now: -***- machine-dbase (Database Edit Abbrev 42/431)---All- This is more informative (and looks nicer) in buffer listings. - Changes to edb-t-timedate.el - Some date formatting funcs now take optional arg SEPARATOR These funcs (w/ default separator): edb-t-timedate1:format-date-mmddyy "/" edb-t-timedate1:format-date-yymmdd "" (empty string) edb-t-timedate1:format-date-ddmmyy "." edb-t-timedate1:format-date-ddmmmyy " " (space) edb-t-timedate1:format-date-yyyymmdd "/" now take an optional second arg SEPARATOR which can be used to override the default listed above. There is presently support for the (previously, and probably always to be, undocumented) vars named by appending "-separator" to the functions' names, but that support will be dropped for EDB 1.28. To convert code that uses the obsoleted vars, find fragments: (let ((FF-separator "*")) (FF date)) and change them to look like: (FF date "*") - New formatting func: edb-t-timedate1:format-date-iso - New builtin displaytype: date-iso For example: (edb-t-timedate1:format-date-iso (edb-t-timedate1:make-date 2006 7 3)) => "2006-07-03" See examples/eicsw.edb for an example usage. - New func: db-set-field-help - New support for field-specific help in `db-field-help' You can now specify a field's help info (string or form that produces a string when evaluated) separately from that of the field's record type; it is no longer necessary to merge the help information in the record type. Field-specific help is displayed first, followed by two newlines, followed by the record type's help. - New attribute :index-function for tagged file layout setup You can now specify `:index-function FUNC' as an attribute override for tagged file layout setup. FUNC is called with one arg, the database object. Relatedly, the manual now documents the restriction on using `db-after-read-hooks' (you can use :index-function, instead). - New support for writing data in a control with inherent data See (info "(./edb.info) Control properties reference") specifically entry `:data TEXT-BLOCK-SPEC'. See also examples/forms-demo2-inherent.edb (a control file). - New configure option: --disable-badnames (see README) - New command: edb-1int-to-single This command helps you to migrate away from "internal file layout", support for which will be dropped in EDB 2.x, by translating that file into a functionally equivalent (more or less) "control with inherent data". See info node by the same name in the EDB manual. - New command: edb-meta This command summarizes EDB state in a new buffer. Since it exposes some internals, it is useful for debugging EDB and/or client programs, but probably not suited for casual users. To try it out in place, build EDB and evaluate the forms: (load-file "lisp/edb-meta.elc") (edb-meta) Once installed, `edb-meta' can be invoked automatically after EDB is loaded (i.e., it is autoloaded). - Advance notice for to-be-dropped items in EDB 1.28 (internal) database-recordfieldspec (internal) database-recordfieldspec-type (internal) database-set-recordfieldspec (spurious) db-tagged-rrfr-hooks (spurious) db-tagged-wrfr-before-hooks (spurious) db-tagged-wrfr-after-hooks Actually "spurious" is kind of a pun: Similar facilities exist for customizing the reading/writing of tagged-format data, when you use control properties, so you SHOULD use them (ha ha). See examples/{eicsw,geneal}.edb. - Maintenance uses files from GNU Automake 1.9.6 - 1.26 | 2005-12-31 - Bugfixes - In View mode, `M-TAB' no longer says "I was confused" This key runs either `db-last-field' or `db-previous-field', depending on whether or Edit minor mode is in effect. EDB used to spuriously display "I was confused" in the echo area, which was probably strictly correct (since it was indeed confused about its state of confusion), but not correct from a user POV, since behavior was as expected in all other respects (point would move to the right place anyway). - In Summary mode, `o' runs command `db-output-record-to-db' It used to be bound to a non-existent command. Also, `db-output-record-to-db' now works from the summary buffer. - Emacs Lisp mode hooks disabled for "Internal Format" read Reading data files in this format uses Emacs Lisp mode, by calling `emacs-lisp-mode', which at some point runs the normal hook `emacs-lisp-mode-hook'. This value is now arranged to be nil for the duration of the read, to avoid potential problems. - Local Variables block no longer limited EDB looks on the last page (area beginning with form-feed, ^L) of the format buffer for the Local Variables block. It used to expect the last page within 3000 characters of point-max. Now, EDB searches the entire buffer (from the end) for the ^L, using point-min if that char is not found. - Dropped buffer-local variable: dbf-hidden-to-end-p Setting/toggling of this sort option is still possible through the interactive (sort) interface. The setting can no longer be saved from one session to the next. - Dropped hook: db-load-hooks To continue to use `db-load-hooks', you must arrange to run the functions in `db-load-hooks' yourself, with the form: (eval-after-load "database" '(run-hooks 'db-load-hooks)) Note that the `run-hooks' form is quoted. - Better support for read-record-from-region function - Point pre-set to beginning of accessible region This basically means that read-record-from-region functions no longer need to begin with `(goto-char (point-min))'. - Return value may be a plist or an alist Previously, read-record-from-region functions had to return a record object, thus requiring allocation and population of a new record using funcs `make-record' and `record-set-field'. While this is still supported (for EDB 1.x), these functions can now opt to return either a property list, with alternating field names and values; or a form `(:alist ALIST)', where ALIST is an association list. In such cases, EDB handles the allocation and population of the record. Also, new function `db-make-record' combines functionality of `make-record' and `record-set-field'. For example: ;; Returning a record the bad old way: (defun my-rrfr () (let ((record (make-record database))) (record-set-field record 'coolsw "SWIG" database) (record-set-field record 'guilty "D.Beazley" database) record)) ;; Returning a record the not-so-bad new way: (defun my-rrfr () (db-make-record database 'coolsw "SWIG" 'guilty "D.Beazley")) ;; Returning a plist: (defun my-rrfr () (list 'coolsw "SWIG" 'guilty "D.Beazley")) ;; Returning an alist: (defun my-rrfr () (cons :alist (list (cons 'coolsw "SWIG") (cons 'guilty "D.Beazley")))) Note that these examples do not actually parse the region. - Changes to the sort interface - All fields visible There is no longer a separate "killed field" stack. Instead, when you type `C-k' on a field, it is moved to the top of the list of nonsignificant fields (whether or not it was itself significant to begin with). Reciprocally, typing `C-y' moves the field at the top of the list of nonsignificant fields to the location under point. `C-u C-y' does the same, but repositions point to be in front of the just-inserted field. `C-y' can only be invoked within the list of significant fields. In this way, all fields are always visible. - You can "drag" a field The default bindings of `M-n' and `M-p' are now to a pair of keyboard macros that essentially arrange to move the field under point "down" and "up", respectively. These make use of `C-k' and `C-y' and inherit their behaviors and restrictions; in particular, dragging works for significant fields only. (Ordering of non-significant fields does not make sense -- that's why they are non-significant!) - Changes to View mode - `+' runs command `db-additional-data-display-buffer' - `x' runs command `db-kill-buffer' - `X' runs command `db-kill-all-buffers' These give a more consistent feel than with `db-exit', which is still available for backwards compatability but not bound in any keymap. Primarily, you no longer need to type `C-u x' to actually kill the buffer. Be careful: A prefix arg now means "force", which discards unsaved changes no questions asked. - "Internal Format" version now 0.7 Note, however, that "internal format" is really a misfeature -- originally this performance hack was worth the maintenance trouble (always associated with exposing internals), but that point was passed about ten years ago. - New functions for managing mark and hide bits The function `edb-tag' returns a database's "tag object" given a name (which, for EDB 1.x, can be `:markedp' or `:hiddenp'). The tag object can be passed to `edb-tagp', `edb-tagx' or `edb-tag-' along with a record to be checked for the tag, set with the tag, or cleared of the tag, respectively. This particular interface (four functions, presently) is upward compatible with EDB 2.x. See node "Setting the mark and hide bits" in the EDB manual for more info. This change is concomitant with the removal, as described in the EDB 1.25 manual, of the "link abstraction", where mark and hide bits lived previously. - Advance notice for to-be-dropped items in EDB 1.27 (alias) db-commit-record (internal) dbc-set-hide-p (internal) db-setup-data-display-buffer (redundant) dbf-reset-on-edit-list (alias) make-record (alias) record-field (alias) record-set-field - FSF street address updated in copyright notices - 1.25 | 2005-01-24 - Bugfix: Edited databases can be saved A severe bug was introduced in EDB 1.24 whereby edited databases could not be saved. The command `db-save-database' would result in the error "Wrong type argument: arrayp, nil" on the first invocation. A follow-on invocation was required to actually do the save. - Bugfix: Computed sort function handles (eq value1 value2) Previously, the somewhat-internal function `db-rs-sortfunc' would return a function that failed to implement "reversal" semantics in the cases where its args were `eq'. - Bugfix: Canoncalization of creation methods (db-convert.el) The function `db-canonicalize-creation-method' now returns a well-formed creation-method object. - Default value for `db-inform-interval' bumped to 100 - In Database View and Summary modes, `t' runs `toggle-truncate-lines' - Encoding for the data file can now be specified You can specify the encoding of the data file by adding to the Local Variables section in the format file a line of the form: edb-data-coding: CODING There is one restriction: If CODING is not one that Emacs can automatically recognize (e.g., `utf-16le'), and the data file is in "internal layout", then both format and data file must be in the same encoding, and you need to do `C-x c CODING ' immediately prior to `M-x db-find-file'. `C-x c' normally runs the command `universal-coding-system-argument'. Unfortunately, this restriction is unlikely to be lifted due to limitations of the `db-find-file' design that cannot be removed for continuing EDB 1.x compatibility. On the other hand, it is not difficult to arrange for Emacs to automatically recognize file encoding. For more info, see file BUGS, bug #5. - More namespace cleaning - db-nosetf.el and db-oldnames.el Cleaning for EDB 1.x function / variable namespace continues. To provide backward (polluting) compatability for applications built on early EDB 1.x, the distribution includes db-nosetf.el and db-oldnames.el. EDB and the examples do not use these files; they will be dropped in EDB 2.x. They can be loaded "manually", like so: (require 'database) ;; Ideally this is sufficient, (require 'db-oldnames) ;; ... but sometimes reality (require 'db-nosetf) ;; ... is where we find ourselves. If you find yourself using a function or variable defined in db-oldnames.el, it's probably a good idea to replace it w/ the newer name so as to be able to avoid loading db-oldnames.el in the first place. An alternative approach, recommended since db-oldnames.el is rather monolithic, is to grep out only the mappings you need into "my-edb-1-oldnames.el" and use that. FYI, the sk4 data file in subdir skram/ lists the interface elements disregarding db-oldnames.el and db-nosetf.el. You can build it by doing "make sk4" in that directory. - new files: edb-t-GROUP.el Functions to support various "type groups" (for lack of a better term) have been moved to edb-t-GROUP.el, from db-time.el (which has been deleted) and db-types.el: GROUP FILE human names edb-t-human-names.el US/UK places edb-t-places-usuk.el EDB 1.x-compatible time/date edb-t-timedate1.el (note the "1") These are all covered in db-oldnames.el, described immediately above, although it is probably better to load them yourself and use the new names if you need them. The naming convention is filename "edb-t-GROUP.el" and prefix (for function and variable names) "edb-t-GROUP:". This change fixes a name (and functionality) conflict between the defunct db-time.el function `parse-time-string' and that provided by some newer versions of Emacs. The naming convention for type groups should sidestep future problems in this vein. - Makefile supports "make edb.dvi" again (disabled EDB 1.22 through 1.24) - GNU make required to build/install EDB Some of the makefiles are now renamed GNUmakefile, and thus require GNU make (perhaps installed as "gmake" or similar) to build and install EDB. This is primarily to support "VPATH builds" w/o resorting to Automake. - Tested against GNU Emacs 21.2 and GNU Emacs from cvs (2005-01-10) - 1.24 | 2004-10-13 - Bugfix: Type registries now less wasteful - Function extended: define-displaytype-from-displayspec - Function extended: define-recordfieldtype-from-recordfieldspec Every invocation of `define-displaytype-from-displayspec' or `define-recordfieldtype-from-recordfieldspec' used to push a new name/object pair onto the respective vars `db-displaytypes' and `db-recordfieldtypes', disregarding the presence of a previously existing pair with the same name. The result was that old definitions could never be found again even though they still took up memory. These functions and the vars they modify have now been changed to ensure that for any name (in each var), only one associated definition is maintained. Additionally, these functions have been extended in two ways: (1) Each takes an optional &rest arg OVERRIDE, as an alternative method for specifying attributes of the type. Using OVERRIDE is recommended for upward compatability and conciseness. (2) The second arg SOURCE can also be the (symbolic) name of a previously defined displayspec or recordfieldspec, respectively; or nil. Together with (1), you can effect modification by specifying the same name for NAME (first arg) and SOURCE, or you can effect inheritence otherwise. EDB does not remember a child type's parent; later changes to a parent type do not propagate to its currently-existing children. - Keybinding changes in Database View mode `F' now runs `dbf-set-summary-format'. `S' `db-sort'. - Function extended: db-tagged-setup This func now takes additional arguments, ATTRS, which are alternating keywords and values specifying attributes of the "tagged database". This method is an alternative to using `database-set-local' (which is to migrate internally within a release or two), and recommended for upward compatability and conciseness. - New distributed file: PLANS This is kind of like TODO but w/o the commitment, and more vague and verbose (PLANS:TODO::courtship:marriage ;-). - New distributed file: BUGS - ANONCVS instructions updated - 1.23 | 2004-08-29 - Bugfix: Functions no longer switched via `fset' EDB used to fset `save-some-buffers' to `db-save-some-buffers', storing the original version away to call later. Even though this was documented, this kind of behavior is now considered a misfeature at best. EDB no longer does this. The command `db-save-some-buffers' is still available, but you have to invoke it as `M-x db-save-some-buffers', or bind a key to it. Likewise, `insert' was fset to `db-insert', an EDB-internal func. [Gratuitous Comment: This one blew my mind when I discovered it. Perhaps all the hand-wringing about speed in the source code comments would not have been necessary had such a fundamental function not been toyed with so capriciously in the first place. Che palle!] - Bugfix: local variable `enable-multibyte-characters' handled specially When writing the database to an external file format, one of the steps is to copy local variables from one buffer to another. Previously this did not call `set-buffer-multibyte', resulting in a "trying to set constant" error. - Command dropped: edb-update Changes in distribution and build practice have rendered this command obsolete. - Variable deprecated: db-default-field-type - Function takes optional third arg: database-set-fieldnames-to-list This pair of changes is explained in some detail in info node "(edb)The database structure". Migration from the former to the latter is encouraged but not enforced (for EDB 1.x). - Command `dbf-set-summary-format' now allows editing of current value - Internal file format now uses `pp' This is still EDB "format 0.6" but now it is written using `pp' primarily for its escaping of newlines (i.e., written as "\n"). Before, newlines in data fields were output verbatim. This should result in greater chance of identifying any data corruption occuring during transmission through varying eol-policy domains (email, through usloth machines, whatever). - Miscellaneous updates and bug fixes in `examples' subdir - New reflection/testing in `skram' subdir This is work-in-progress. The idea is to use EDB to track changes to EDB. Version control is one thing, design control is another... Yes, EDB dares to venture into the dreaded land of Project Manglement! Actually, like all things to do w/ manglement, this demonstrates two aspects of EDB having to deal w/ trust: 1/ it is trustworthy enough to run scripts or participate in editing sessions where its current over-reaching of namespace is tolerable; and 2/ it requires manual verification, still, despite 1/. - 1.22 | 2004-06-02 This is a cleanup release (perhaps one of several) following maintainership transfer from Michael Ernst, the author of EDB, to Thien-Thi Nguyen, the slowly-searching student of EDB (and other works of codified thought). Cleanup means adding "./configure && make && make install" support (including commonly related things like "make dist", NEWS file, etc); minor upgrading of the elisp dialect and style; and bundling the examples. A request for outstanding bugfixes posted to one of the newsgroups has gone unanswered to date, so this release includes no bugfixes. The programming interface has not changed. Those elements mentioned in the info pages are guaranteed to NOT change for all 1.x versions of EDB. If you have written an application based on EDB that uses undocumented elements, you can either contribute doc patches (which if accepted would result in those elements being guaranteed to NOT change), or prepare yourself for the necessity of rewriting that particular code if/when the undocumented elements change. - 1.21 AND PRIOR Please refer to theory.lcs.mit.edu:/pub/emacs/edb/ for prior releases of EDB and related information. Copyright information: Permission is granted to anyone to make or distribute verbatim copies of this document as received, in any medium, provided that the copyright notice and this permission notice are preserved, thus giving the recipient permission to redistribute in turn. Permission is granted to distribute modified versions of this document, or of portions of it, under the above conditions, provided also that they carry prominent notices stating who last changed them. Local Variables: mode: outline outline-regexp: "\\([ ][ ]\\)*- " coding: utf-8 fill-column: 72 fill-prefix: "\t" End: edb-1.31/README0000444000175000017500000000714010745370011011242 0ustar ttnttnWelcome! ======== This directory contains EDB, the Emacs Database. EDB was written by Michael Ernst , and is being maintained by Thien-Thi Nguyen . EDB homepage: Dependencies ============ GNU make that supports VPATH -- build/install GNU Emacs 22.x or later -- build/install/run Installation ============ To install EDB, unpack the tarball, change into the resulting directory (usually named edb-${VERSION}), and issue the three commands: ./configure make make check # optional but recommended make install This byte-compiles the .el files, and copies .el and .elc files to ${sitelisp}/edb, and edb.info to ${infodir}, creating those directories first if necessary. Normally, these variables have the values: ${prefix} /usr/local ${datadir} ${prefix}/share ${sitelisp} ${datadir}/emacs/site-lisp ${infodir} ${prefix}/info To use DIR instead of "/usr/local" for ${prefix} include the option `--prefix DIR' to the configure script. To choose an alternate ${sitelisp}, use the option `--with-sitelisp=DIR'. You can use the `--help' option to see full details. For backward-compatibility the normal installation includes some function aliases that can be considered "namespace-polluting". To arrange to not install these, you can use the configure option `--disable-badnames'. With this option, the files db-nosetf.el and db-oldnames.el are not installed, and neither are the aliases: maprecords define-displaytype-from-displayspec define-recordfieldtype-from-recordfieldspec define-enum-type See the manual for new names to use, instead. By default, the configure script looks for and uses the first "emacs" executable found in a directory named in the PATH env var. To use another Emacs, you can either change PATH, or you can specify the env var EMACS to name the new executable. The latter approach overrides the PATH search. For example: EMACS=$HOME/emacs-22/src/emacs export EMACS ./configure ... The specified (or found) Emacs is set in the various makefiles. You can furthermore (at runtime) select another Emacs to use by specifying the `EMACS' variable in the command-line for make. For example: make check EMACS=$HOME/picky-emacs/src/emacs After installation, the unpacked directory can be deleted. Note that installation does not place files directly in the ${sitelisp} directory, but rather a subdirectory named "edb". It is assumed there exists the file ${sitelisp}/subdirs.el that is responsible for adding ${sitelisp}/edb to the Emacs `load-path'. If this is not the case, you can create one to do the job, with contents: (if (fboundp 'normal-top-level-add-subdirs-to-load-path) (normal-top-level-add-subdirs-to-load-path)) This has been verified to work with GNU Emacs 21.3. Usage ===== To experiment, evaluate in this directory: (add-to-list 'load-path default-directory) (require 'database) Then you can do Dired in subdirs `examples' and `skram', move point to various data and .edb files, and use the command: (defun my-dired-edb-interact () (interactive) (let ((filename (dired-get-filename))) (if (string-match "[.]edb$" filename) (edb-interact filename nil) (db-find-file filename)))) Full details are in the documentation, highly recommended for both end users and programmers. Reporting Bugs ============== If you find a problem with EDB that is not explained in the documentation, please send a bug report to . Include EDB version and as concise a test case as possible (that reproduces the problem). edb-1.31/THANKS0000444000175000017500000000034411016261542011274 0ustar ttnttnTHANKS -*-coding:utf-8;-*- These kind people have helped improve EDB. Phillip Lord Bob Newell Erich Wälde Janusz S. Bieñ NAKAMURA Toshikazu Michael Ernst (Please contact ttn if you should be on this list but aren't.) edb-1.31/TODO0000444000175000017500000001223011016451110011036 0ustar ttnttn- 1.32 - document API comprehensively - functions - variables - finalize control properties for `single' schema-schema - 2.01 - drop - "internal file layout" - defstructs - special handling for format and aux files - `db-find-file' - various hooks / vars - aliases - maprecords - define-displaytype-from-displayspec - define-recordfieldtype-from-recordfieldspec - define-enum-type - move to "edb-" prefix namespace - observer-single and observer-batch protocol - add :include control property - support connection-based namespaces - source - data types - display types - eventually - write edb-t-timedate.el using abstractions provided by Emacs - eliminate @findex and @vindex in docs - use examples in "make check" - use selected bugs in "make check" - use term "table" for collection of records - use term "database" for collection of tables - synthetic/dynamic/remote/etc data - reduce insert/delete lossage, use text properties and/or overlays - allow ring or ewoc as "virtual vov" - use external tar(1) to access encapsulated file tree - extend db-rdb.el to wrap subprocess interaction - redesign indexing to avoid befuddling OBOE potential - think! - Namespace cleaning Everything should be prefixed w/ "database-" or "db[a-z]-" or "edb-" for EDB 1.x. This is incompatible w/ early EDB 1.x if we take the hard-line approach of guaranteeing no change from what was previously documented. To avoid the hobgoblin-of-small-minds situation, we partition the documented items into those that are sound (likely to be carried forward to EDB 2.x) and those that are unsound (should have been hidden by higher-level abstractions from the beginning, but unfortunately wasn't). Each item or group of items, whether sound or unsound, must be addressed on a case by case basis. The goal is to introduce incompatibility only where it is not so impactful to current applications (the sample set being those databases in the `examples' subdirectory plus any requests from afield -- to date, this latter category has been thunderously silent but who knows what the future will drag in from the past). Where incompatibility is deemed to be of high impact (the item is used and is either sound, or if unsound, unsound only in implementation), the docs are to be revised to deprecate (1.x) and eliminate (2.x) the item. Deprecations must be accompanied by some kind of migration path or plan. For incompatibility of low impact, the item can simply be deleted from the docs after being marked as "documentation to be deleted" for at least one release. For 2.x, everything should be prefixed with "edb-". The nice hack would be to move 1.x to a point such that switching a late-1.x-conforming application to 2.x can be done via a one-line sed/elisp script only. Internals should use "edb--". - Terminology tweak By EDB 2.x, docs and comments should define "database" as a "collection of tables", "table" as a "collection of rows", and "row" as an ordered tuple of "columns". Also, decoupling of control connection, reads and commits should be made very clear in documentation and function names. In this terminology, past (EDB 1.x) behavior can be described as "mostly-direct manipulation of a single-table database". - Higher abstraction level for EDB 2.x The API for EDB 2.x is to focus on three areas: "conversion specification", "data source specification" and "presentation specification". In some sense, 2.x is to give up some of the flexibility of 1.x (largely unused in practice) in exchange for a cleaner overall architecture. Where possible, specification is to be done declaratively rather than functionally. The file-reading and -writing bits of EDB 1.x are to be generalized into "conversion for read" and "conversion for write" function pairs. The set of built-in pairs to be distributed w/ EDB is to be extendable by applications: "conversion specification". Selected bits of the `displayspec', `recordfieldspec' and `sepinfo' structures are to be folded into the "data source specification". Comingling of data source and data source specification, as implemented in EDB 1.x using local variables, is to be dropped. The 2.x "native data source" is to be a tar file (maybe gzipped) that may or may not be self-contained; it may specify the actual data source as some "non-native data source" outside itself. Non-native data sources are to include files, connections to network-available databases (e.g., PostgreSQL or web queries), and generally, completely synthetic sources (i.e., the output of elisp functions). Applications do not need to know about "link" or "record index". The `link' structure, ring-management code, and `displayspec' structure are to be replaced by calls to ewoc.el functions (for ordered views) and a congruent hash-table based implementation (for unordered views). Support for indexing by the application is to be generalized into r/w/observe access to per-record metainfo, opaque to EDB. These implementation details are to be further abstracted as "presentation specification". - Better support for relational databases for EDB 3.x edb-1.31/configure.ac0000444000175000017500000000364311016452223012652 0ustar ttnttn# configure.ac # # Copyright (C) 2006,2007,2008 Thien-Thi Nguyen # # This file is part of EDB. # # EDB 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 3, or (at your option) any later # version. # # EDB 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 EDB; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. AC_INIT([EDB],[1.31],[ttn@gnuvola.org]) AC_PROG_INSTALL # allow env override but do not get fooled by EMACS=t test t = "$EMACS" && unset EMACS # the next line does nothing if var EMACS is already set AC_CHECK_PROG([EMACS], [emacs], [emacs]) if test "x$EMACS" = x ; then AC_MSG_ERROR([emacs not found; required!]) fi AC_ARG_WITH([sitelisp], AS_HELP_STRING([--with-sitelisp=DIR], [Override the default site-lisp directory]), sitelisp="$withval", sitelisp="$datadir/emacs/site-lisp") AC_SUBST(sitelisp) badnamesp=true AC_ARG_ENABLE([badnames], AS_HELP_STRING([--disable-badnames], [Do not support backward-compatible but namespace-polluting aliases (see README)]), [test "$enableval" = no && badnamesp=false]) AC_SUBST(badnamesp) AC_CONFIG_FILES([ GNUmakefile doc/GNUmakefile lisp/GNUmakefile tests/GNUmakefile skram/GNUmakefile ]) AC_CONFIG_FILES([tests/ebatch],[chmod +x tests/ebatch]) AC_CONFIG_COMMANDS([symlinks],[ exdir="${srcdir}/examples" test -L "$exdir/passwd" || ln -s /etc/passwd "$exdir" test -L "$exdir/null" || ln -s /dev/null "$exdir" ]) AC_OUTPUT # configure.ac ends here edb-1.31/examples/0000755000175000017500000000000011016452347012205 5ustar ttnttnedb-1.31/examples/ChangeLog0000444000175000017500000003351510745370011013757 0ustar ttnttn2007-12-29 Thien-Thi Nguyen * tepdb.dba (tep-report): Make into a func; update callers. (tep-prettify-address-report): Incorporate into unique caller. 2007-12-29 Thien-Thi Nguyen * tepdb.dba (tepdb:after-read): Fix omission bug introduced 2006-07-12: Include (empty) arg list. 2007-12-26 Thien-Thi Nguyen * www-links2, www-links2.edb, www-links3, www-links3.edb: New files. 2007-12-12 Thien-Thi Nguyen * www-links, www-links.edb: New files. 2007-12-05 Thien-Thi Nguyen * passwd.edb, passwd.fmt: For display, bump width of `username' to 20. 2007-05-26 Thien-Thi Nguyen * null.edb: Move :EDB after initial comment block. 2007-04-24 Thien-Thi Nguyen * null.edb: New file. 2006-07-25 Thien-Thi Nguyen * arb-demo-regexp.edb, arb-demo.edb, eicsw.edb * forms-demo2-inherent.edb, forms-demo2.edb, names.edb, * passwd.edb, rolo-jik.edb, retired.edb, skram.edb: Make sure all text blocks end with :EOTB. 2006-07-13 Thien-Thi Nguyen * geneal.dat, geneal.edb: New files. 2006-07-12 Thien-Thi Nguyen * tepdb.dba: Use `add-hook' and `remove-hook'. (tepdb:after-read): New func. 2006-07-12 Thien-Thi Nguyen * edbibtex/bibtex.dba: Use `add-hook'. * edbibtex/edbibtex.el (BibTeX-set-up-db-buffer): Fix omission bug: Remove this function from `db-before-read-hooks' when done. 2006-07-03 Thien-Thi Nguyen * eicsw.fmt: Use `date-iso' for Installed and Last Update fields. * eicsw.edb: Use `date-iso' in the display text block. * eicsw.dba, eicsw.edb (suredate): For this recordfieldtype, specify YYYY-MM-DD date format for :actual->stored. 2006-06-30 Thien-Thi Nguyen * eicsw.dba, eicsw.edb: Use `edb-define-enumtype'. 2006-06-10 Thien-Thi Nguyen * eicsw.dba, eicsw.edb: Throughout, use `edb-define-displaytype' and `edb-define-recordfieldtype'. 2006-06-08 Thien-Thi Nguyen * edbibtex/edbibtex.el (BibTeX-wrfr): Replace match w/ literal text. 2006-06-08 Thien-Thi Nguyen * tepdb.dba (tep-year-report): Replace match w/ literal text. (tep-nickname-report): Likewise. (tep-prettify-address-report): Likewise. Also, use `delete-region'. 2006-06-08 Thien-Thi Nguyen * edbibtex/edbibtex.el: Don't modify `db-change-format' definition. 2006-06-05 Thien-Thi Nguyen * intro-and-addr: Mention db-convert.el removal. 2005-12-31 Thien-Thi Nguyen * forms-demo2-inherent.edb: New file. 2005-12-31 Thien-Thi Nguyen * edbibtex/edbibtex.el, arb-demo-regexp.dba: * arb-demo.dba, eicsw.dba, rolo-jik.dba, tepdb.dba: Use `db-record-field' and/or `db-record-set-field'. 2005-12-30 Thien-Thi Nguyen * tepdb.dba (tep-labels, tep-labels/marked): Use `db-maprecords'. * edbibtex/edbibtex.el (BibTeX-define-abbreviations): Likewise. 2005-12-28 Thien-Thi Nguyen * arb-demo-regexp.edb: Use vectors for :field-separator and :cruft. 2005-12-19 Thien-Thi Nguyen * eicsw.edb: Rewrite :record-defaults value as lambda expression. 2005-12-18 Thien-Thi Nguyen * eicsw.dba (swdb-record-defaults): Use `current-time-string'. * eicsw.edb (swdb-record-defaults): Likewise. 2005-12-18 Thien-Thi Nguyen * rolo-jik.edb: Remove :field-setter. (rolodex-change-date): Use `dbf-this-record-set-field'. 2005-12-15 Thien-Thi Nguyen * passwd.edb: Specify `integer' for fields `uid' and `gid'. 2005-12-11 Thien-Thi Nguyen * forms-demo2.edb: Use vector for :substitutions. 2005-12-10 Thien-Thi Nguyen * forms-demo2.edb: Use :field-order. 2005-12-07 Thien-Thi Nguyen * rolo-jik.edb (rolo-jik-regexp): Fix typo. (rolodex-write-record): Use nil arglist. 2005-12-06 Thien-Thi Nguyen * forms-demo2-int.dat, tepdb: Rewrite in "format 0.7". 2005-12-05 Thien-Thi Nguyen * eicsw.edb: Use `define-enum-type', `define-displaytype-from-displayspec' and `define-recordfieldtype-from-recordfieldspec'. 2005-12-05 Thien-Thi Nguyen * eicsw.edb: Convert :require to `require' form. 2005-11-28 Thien-Thi Nguyen * arb-demo-regexp.edb: New file. 2005-11-28 Thien-Thi Nguyen * eicsw.edb: Fix typo in :summary-format. 2005-11-28 Thien-Thi Nguyen * rolo-jik.dba, rolo-jik.edb: No longer set `post-last-string' slot in `record-sepinfo' slot in database. 2005-11-27 Thien-Thi Nguyen * arb-demo.dba (arb-demo-rrfr): Remove `(goto-char (point-min))'. * rolo-jik.dba (rolodex-rrfr): Likewise. 2005-11-27 Thien-Thi Nguyen * rolo-jik.edb (rolo-jik-regexp): New var. (rolodex-read-record): Use `rolo-jik-regexp'. Return plist. * arb-demo.edb (arb-demo-read-record): Return plist. 2005-11-26 Thien-Thi Nguyen * arb-demo.fmt: Remove local-variables block. 2005-11-23 Thien-Thi Nguyen * arb-demo.dba (arb-demo-rrfr): Return plist. * rolo-jik.dba (rolodex-rrfr): Likewise. 2005-11-19 Thien-Thi Nguyen * tepdb.dba: In `db-after-read-hooks', set `db-edit-mode-hooks', after making it a buffer-local var, not `dbf-reset-on-edit-list'. 2005-11-19 Thien-Thi Nguyen * tepdb.dba (tep-report, tep-local-labels): Pass nil to `database-sort'. 2005-11-19 Thien-Thi Nguyen * arb-demo.edb: Remove :post-last-record. Add :cruft. 2005-11-19 Thien-Thi Nguyen * edbibtex/edbibtex.el (BibTeX-set-format-from-data) (BibTeX-validate-record, BibTeX-rrfr): No longer pass DATABASE to `record-set-field'. 2005-11-19 Thien-Thi Nguyen * edbibtex/edbibtex.el (BibTeX-define-abbreviations): No longer specify DB to `maprecords'. 2005-11-19 Thien-Thi Nguyen * tebdb.dba (tep-labels, tep-labels/marked): No longer specify DB to `maprecords'. 2005-11-19 Thien-Thi Nguyen * rolo-jik.dba (rolodex-wrfr): Omit DATABASE arg to `record-field'. (rolodex-before-display): Likewise. Also, make RECORD optional. If omitted, pass t as RECORD to `record-field'. (rolodex-change-function): Call `rolodex-before-display' w/o args. 2005-11-19 Thien-Thi Nguyen * tepdb.dba (tep-record-fullname): No longer take DATABASE or pass it to `record-field'. (tep-record-biz-address, tep-record-home-address): Likewise. (tep-homeaddr-change-hook, tep-bizaddr-change-hook): Pass t as RECORD, and no longer pass DATABASE to `record-field'. (tep-labels, tep-labels/marked): Update calls to `tep-record-fullname', `tep-record-biz-address' and `tep-record-home-address'. * edbibtex/edbibtex.el (BibTeX-define-abbreviations, BibTeX-wrfr) (BibTeX-set-format-from-data, BibTeX-check-abbreviations) (BibTeX-validate-record): No longer pass DATABASE to `record-field'. 2005-11-19 Thien-Thi Nguyen * arb-demo.dba (arb-demo-wrfr, arb-demo-set-format-from-data): Omit DATABASE arg to `record-field'. * arb-demo-regexp.dba (arb-demo-wrfr): Likewise. 2005-11-18 Thien-Thi Nguyen * rolo-jik.edb (rolodex-read-record): Remove unused auto var. 2005-11-18 Thien-Thi Nguyen * arb-demo.dba (arb-demo-rrfr): Use `db-make-record'. * rolo-jik.dba (rolodex-rrfr): Likewise. 2005-10-25 Thien-Thi Nguyen * arb-demo-regexp.dba: No longer specify default format file. 2005-10-24 Thien-Thi Nguyen * eicsw.dba, eicsw.edb: No longer specify data file. 2005-10-17 Thien-Thi Nguyen * eicsw.dba, eicsw.edb: Fix typo: Use correct name for data file. 2005-05-27 Thien-Thi Nguyen * edbibtex/gpl.texinfo: Delete file. * edbibtex/edbibtex.texinfo (Copying): Replace @include w/ copyright notice. (Installation): No longer mention gpl.texinfo. * edbibtex/Makefile (DOCUMENTATION): Remove gpl.texinfo. 2005-04-09 Thien-Thi Nguyen * passwd.fmt: Coalesce code in local variables block into one `let' form. 2005-04-08 Thien-Thi Nguyen * edbibtex/edbibtex.el (BibTeX-make-record): Use length of `fieldnames' value. 2005-01-19 Thien-Thi Nguyen * tepdb.dba (tep-report): Use field names directly in field-priorities list. 2005-01-18 Thien-Thi Nguyen * names.fmt (edb-data-coding): Use `iso-safe'. 2005-01-18 Thien-Thi Nguyen * eicsw.dba: Use `db-string-or-nil->string', `db-string-or-nil-order-ci', `db-string-or-nil-lessp-ci' and `db-string-or-nil-match-function'. * eicsw.edb: Likewise. 2005-01-15 Thien-Thi Nguyen * eicsw.dba: Require `edb-t-timedate1'. Use `edb-t-timedate1:parse-date-string'. * eicsw.edb: Add :require for `edb-t-timedate1'. Use `edb-t-timedate1:parse-date-string'. 2005-01-14 Thien-Thi Nguyen * arb-demo-regexp.dba: Use `setf' forms. * arb-demo.dba: Likewise. * eicsw.dba: Likewise. * forms-demo2.fmt: Likewise. * passwd.fmt: Likewise. * rolo-jik.dba: Likewise. * rolo-jik.edb: Likewise. * edbibtex/bibtex.dba: Likewise. 2005-01-13 Thien-Thi Nguyen * names.fmt (edb-data-coding): Add local variable. 2005-01-13 Thien-Thi Nguyen * arb-demo.edb, eicsw.edb, forms-demo2.edb: New files. * names.edb, passwd.edb, rolo-jik.edb: New files. 2004-10-07 Thien-Thi Nguyen * eicsw.dba: Specify overriding attributes via `db-tagged-setup' arg instead of through multiple `database-set-local' calls. 2004-10-06 Thien-Thi Nguyen * tepdb.dba (tep-report-directory): Use `member'. Also, for default case, return "/tmp". 2004-10-06 Thien-Thi Nguyen * tepdb.dba (tep-report): Update syntax for quasiquote and unquote. 2004-10-06 Thien-Thi Nguyen * edbibtex/edbibtex.el: No longer use `function' around lambda forms. Convert `function' with symbol arg to `quote'. * tepdb.dba: Likewise. * eicsw.dba: Likewise. * btxdb.el: Likewise. 2004-10-05 Thien-Thi Nguyen * eicsw.dba: No longer modify recordfieldtype `date' slot `stored->actual'. (suredate): New recordfieldtype. Use it instead of `date'. 2004-09-17 Thien-Thi Nguyen * tepdba.dba (tep-prettify-address-report): Replace `replace-string' with `(while (search-forward...) ...)'. (tep-year-report): Likewise. (tep-nickname-report): Likewise. 2004-09-09 Thien-Thi Nguyen * rolo-jik.dba (newlines->semis): Use `replace-regexp-in-string'. (semis->newlines): Likewise. 2004-09-03 Thien-Thi Nguyen * eicsw.dba: Throughout, use new interface for `define-displaytype-from-displayspec' and `define-recordfieldtype-from-recordfieldspec'. 2004-08-29 Thien-Thi Nguyen * edbibtex/bibtex.dba (db-default-field-type): No longer set this var. 2004-08-28 Thien-Thi Nguyen * tepdb.dba (tep-labels): Delete unused local `db'. (tep-labels/marked): Likewise. Also, use `maprecords' instead of `maplinks'. 2004-08-28 Thien-Thi Nguyen * edbibtex/edbibtex.el (BibTeX-define-abbreviations): Use `maprecords'. 2004-08-27 Thien-Thi Nguyen * tepdb.dba (db-after-read-hooks): Fix misplaced paren bug: Move last action within `lambda' instead of within `function'. 2004-08-27 Thien-Thi Nguyen * rolo-jik.dba (newlines->semis): Use `db-string-replace-regexp-2'. (semis->newlines): Likewise. 2004-08-27 Thien-Thi Nguyen * rolo-jik.dba (match-string): Delete func; Emacs provides a subr. 2004-08-26 Thien-Thi Nguyen * names.dat: Tabify. 2004-08-20 Thien-Thi Nguyen * arb-demo.dba (arb-demo-rrfr): Use `match-string'. 2004-05-15 Thien-Thi Nguyen * README: Initial checkin from Michael Ernst. * forms-demo2.fmt, rolo-jik.dba, forms-demo2.report, rolo-jik.doc, arb-demo, geneal, rolo-jik.fmt, arb-demo-regexp, eicsw.dat, intro-and-addr, tepdb, arb-demo-regexp.dba, eicsw.dba, names.dat, tepdb.dba, arb-demo.dba, eicsw.fmt, names.fmt, tepdb.fmt, arb-demo.fmt, forms-demo2-int.dat, passwd.fmt, tepdb.instr, arb-demo.home-fmt, forms-demo2.dat, rolo-jik.dat: Likewise. * btxdb, btxdb/examples: New directories. * btxdb/COPYING: Initial checkin from Michael Ernst. * btxdb/COPYING, btxdb/ChangeLog, btxdb/Makefile, btxdb/README, btxdb/TODO, btxdb/article.fmt, btxdb/bibtex.fmt, btxdb/book.fmt, btxdb/booklet.fmt, btxdb/btxdb.el, btxdb/btxdb.texi, btxdb/conference.fmt, btxdb/gpl.texinfo, btxdb/inbook.fmt, btxdb/incollection.fmt, btxdb/inproceedings.fmt, btxdb/journals-abbrev.rep, btxdb/journals-full.rep, btxdb/journals.dat, btxdb/journals.dba, btxdb/journals.fmt, btxdb/manual.fmt, btxdb/mastersthesis.fmt, btxdb/misc.fmt, btxdb/phdthesis.fmt, btxdb/proceedings.fmt, btxdb/techreport.fmt, btxdb/unpublished.fmt, btxdb/examples/bibtex.bib: Likewise. * edbibtex: New directory. * edbibtex/Makefile: Initial checkin from Michael Ernst. * edbibtex/article.fmt, edbibtex/bibtex.dba, edbibtex/bibtex.fmt, edbibtex/book.fmt, edbibtex/booklet.fmt, edbibtex/compile.el, edbibtex/edbibtex.el, edbibtex/edbibtex.texinfo, edbibtex/gpl.texinfo, edbibtex/inbook.fmt, edbibtex/incollection.fmt, edbibtex/inproceedings.fmt, edbibtex/manual.fmt, edbibtex/mastersthesis.fmt, edbibtex/misc.fmt, edbibtex/phdthesis.fmt, edbibtex/preamble.fmt, edbibtex/proceedings.fmt, edbibtex/string.fmt, edbibtex/techreport.fmt, edbibtex/unpublished.fmt: Likewise. edb-1.31/examples/README0000444000175000017500000000375310745370011013066 0ustar ttnttnThis directory contains examples of using EDB. The following files are available; see the documentation for file naming conventions. README This file. This is not EDB's README file, only that for its examples. forms-demo2.dat The database supplied as "demo2" of the Forms package. forms-demo2.fmt forms-demo2.report forms-demo2-int.dat The same database in EDB internal layout. arb-demo An example database in "arbitrary" format; it uses functions arb-demo.dba rather than rules to read and write the disk file. It also arb-demo.fmt uses an alternate format file. arb-demo.home-fmt arb-demo-regexp The same database as that above, but with its layout arb-demo-regexp.dba specified by a set of regular expressions. When you do `db-find-file' on arb-demo-regexp, EDB will ask for its display format; you should use arb-demo.fmt. eicsw.dat Alan Stebbens's EIC software database, which uses enumerated eicsw.fmt types and the date type. eicsw.dba passwd.fmt A format file for use with /etc/passwd; do db-find-file on /etc/passwd and specify this file as the format file. tepdb Michael Ernst's address database in internal file layout; tepdb.fmt includes change functions, aging of data, reports, mailing tepdb.dba labels, and usage instructions. tepdb.instr rolo-jik.dat Jonathan Kamens's rolodex database; includes user-definable rolo-jik.fmt fields and dynamic data display buffer alignment. rolo-jik.dba rolo-jik.doc intro-and-addr Bob Chassell's introduction to EDB for the complete novice, plus an address database and code for producing mailing labels. btxdb.README Instructions for retrieving Thorsten Ohl's BibTeX database. edbibtex Michael Burschik's BibTeX database and sample format files. Includes documentation, example databases, and more. geneal Instructions for retrieving Michael Patton's geneal database, which includes inter-record links and tagged file layout. www-links* URLs and associated metadata. More examples are welcome! Please send them to . edb-1.31/examples/arb-demo0000644000175000017500000000051410745370011013611 0ustar ttnttnPlace: 253 Commonwealth Avenue Time: Noon Purpose: Barbecue Place: 1600 Pennsylvania Avenue Time: March, 1993 Purpose: Moving in Place: Dentist's Office Time: Never! Purpose: Fill cavities, root canal Place: Home Time: Midnight Purpose: Sleep Place: Other places Time: Other times Purpose: Other things edb-1.31/examples/arb-demo-regexp0000644000175000017500000000051410745370011015101 0ustar ttnttnPlace: 253 Commonwealth Avenue Time: Noon Purpose: Barbecue Place: 1600 Pennsylvania Avenue Time: March, 1993 Purpose: Moving in Place: Dentist's Office Time: Never! Purpose: Fill cavities, root canal Place: Home Time: Midnight Purpose: Sleep Place: Other places Time: Other times Purpose: Other things edb-1.31/examples/arb-demo-regexp.dba0000444000175000017500000000173410745370011015631 0ustar ttnttn;;; arb-demo-regexp.dba -*- emacs-lisp -*- (setf (database-print-name database) "Mike's Time & Place Database [regexp version]") (database-set-fieldnames-to-list database '(place time purpose)) ;;; Reading (let ((r-si (database-record-sepinfo database)) (f-si (database-field-sepinfo database))) (setf ;; Records (sepinfo-sep-string r-si) "\n\n" (sepinfo-post-last-string r-si) "\n" ;; Fields (sepinfo-pre-first-regexp f-si) "^[^:]*:[ \t]*" (sepinfo-pre-first-regexp-submatch f-si) 0 (sepinfo-sep-regexp f-si) "\n[^:]*:[ \t]*" (sepinfo-sep-regexp-submatch f-si) 0)) ;;; Writing (defun arb-demo-wrfr (record) (insert "Place: " (db-record-field record 'place) "\nTime: " (db-record-field record 'time) "\nPurpose: " (db-record-field record 'purpose))) (setf (database-write-region-from-record database) 'arb-demo-wrfr) ;;; arb-demo-regexp.dba ends here edb-1.31/examples/arb-demo-regexp.edb0000444000175000017500000000241010745370011015625 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "Mike's Time & Place Database [regexp version]" :fields [place time purpose] :record-separator "\n\n" :field-separator ["\n[^:]*:[ \t]*" 0] :cruft [[nil "\n"] [["^[^:]*:[ \t]*" 0] nil]] :write-record (defun arb-demo-wrfr (place time purpose) (insert "Place: " place "\nTime: " time "\nPurpose: " purpose)) :display t === Mike's Time & Place Database === Place: \place Time: \time Purpose: \purpose :EOTB ;;; arb-demo-regexp.edb ends here edb-1.31/examples/arb-demo.dba0000444000175000017500000000330710745370011014337 0ustar ttnttn;;; arb-demo.dba -*- emacs-lisp -*- ;;; ;;; This database auxiliary file is for use with the database file arb-demo. (database-set-fieldnames-to-list database '(place time purpose)) (setf (database-print-name database) "Mike's Time & Place Database") (let ((r-si (database-record-sepinfo database))) (setf ;; Separating (sepinfo-sep-string r-si) "\n\n" ;; Extra characters at end of file (sepinfo-post-last-string r-si) "\n")) (setf ;; Reading (database-read-record-from-region database) 'arb-demo-rrfr ;; Writing (database-write-region-from-record database) 'arb-demo-wrfr) ;; This function (correctly) assumes the buffer is narrowed to the region. (defun arb-demo-rrfr () (if (re-search-forward "Place:[ \t]*\\(.*\\)\nTime:[ \t]*\\(.*\\)\nPurpose:[ \t]*\\(.*\\)" nil t) (list 'place (match-string 1) 'time (match-string 2) 'purpose (match-string 3)) (error "arb-demo-rrfr: This line region didn't look like a record to me."))) (defun arb-demo-wrfr (record) (insert "Place: " (db-record-field record 'place) "\nTime: " (db-record-field record 'time) "\nPurpose: " (db-record-field record 'purpose))) ;; Automatically choose the appropriate format for the current record. (defun arb-demo-set-format-from-data (record) (if (string= "Home" (db-record-field record 'place)) (db-change-format "home format") (db-change-format "non-home format"))) (setq dbf-format-name-spec-alist '(("home format" . "arb-demo.home-fmt") ("non-home format" . "arb-demo.fmt")) dbf-before-display-record-function 'arb-demo-set-format-from-data) ;;; arb-demo.dba ends here edb-1.31/examples/arb-demo.edb0000444000175000017500000000347310745370011014347 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "Mike's Time & Place Database" :fields [place time purpose] :record-separator "\n\n" :read-record (defun arb-demo-read-record () (if (re-search-forward "Place:[ \t]*\\(.*\\)\nTime:[ \t]*\\(.*\\)\nPurpose:[ \t]*\\(.*\\)" nil t) (list 'place (match-string 1) 'time (match-string 2) 'purpose (match-string 3)) (error "This region didn't look like a record to me."))) :write-record (defun arb-demo-write-record (place time purpose) (insert "Place: " place "\nTime: " time "\nPurpose: " purpose)) :cruft [[nil "\n"] [nil nil]] :choose-display (defun arb-demo-select-format-from-data (place) (if (string= "Home" place) "home format" "non-home format")) :display (:name "home format") === Mike's Time & Home Database === Purpose: \purpose Time: \time ** This activity is at home. ** :EOTB :display (:name "non-home format") === Mike's Time & Place Database === Place: \place Time: \time Purpose: \purpose :EOTB ;;; arb-demo.edb ends here edb-1.31/examples/arb-demo.fmt0000444000175000017500000000013110745370011014367 0ustar ttnttn=== Mike's Time & Place Database === Place: \place Time: \time Purpose: \purpose edb-1.31/examples/arb-demo.home-fmt0000444000175000017500000000015010745370011015316 0ustar ttnttn=== Mike's Time & Home Database === Purpose: \purpose Time: \time ** This activity is at home. ** edb-1.31/examples/btxdb.README0000444000175000017500000000234110745370011014160 0ustar ttnttnDate: Wed, 30 Dec 92 22:05:15 -0500 From: ohl@chico.harvard.edu (Thorsten Ohl) To: edb-list@theory.lcs.mit.edu Subject: Editing BibTeX files w/ EDB Some time ago someone asked about a BibTeX interface for EDB. Since there was no response and I would also like to have something of this sort, I hacked a first approximation over the holidays. * It's rough. * It has no documentation. * I have made almost no efforts to parse general BibTeX files, just the subset I use (or rather a subset thereof). * ... but it might be better than nothing. I have put it up for anonymous ftp on `chico.harvard.edu' in the directory `pub'. The code is in `btxdb-0.3.tar.Z'. The file `bibtex.dat' serves as an example database. [ As of early 1994, the definitive place to get the latest version was ftp://crunch.ikp.physik.th-darmstadt.de/pub/ohl/misc/btxdb-0.6.tar.gz ] Comments, suggestions, and code are welcome. But I can make no support commitments ... Happy GNU Year, -tho /// Thorsten Ohl, Physics Dept, Harvard University, Cambridge, MA 02138, USA //////// net: ohl@physics.harvard.edu, ohl@crunch.ikp.physik.th-darmstadt.de ////////////////////////////// voice: +1-617-495-3219, fax: +1-617-496-8396 edb-1.31/examples/btxdb/0000755000175000017500000000000011016452347013310 5ustar ttnttnedb-1.31/examples/btxdb/ChangeLog0000444000175000017500000002313310745370011015055 0ustar ttnttn2006-07-12 Thien-Thi Nguyen * btxdb.el (btxdb:read-comments): Fix omission bug: Remove this function from `db-before-read-hooks' when done. (btxdb:stored->actual): New func. (btxdb:initialize): Use `btxdb:stored->actual'. 2006-07-11 Thien-Thi Nguyen * btxdb.el (btxdb:initialize): Don't copy and modify recordfieldspecs. Instead, use `db-set-field-help'. 2006-06-30 Thien-Thi Nguyen * btxdb.el: Use `edb-define-enumtype'. 2006-06-10 Thien-Thi Nguyen * btxdb.el (btxdb:initialize): Fix omission bug: Specify `string-or-nil' as default recordfieldtype. 2006-06-10 Thien-Thi Nguyen * btxdb.el: Throughout, use `edb-define-displaytype' and `edb-define-recordfieldtype'. 2006-06-08 Thien-Thi Nguyen * btxdb.el (btxdb:set-format-from-data): Use `db-change-format'. 2006-06-08 Thien-Thi Nguyen * btxdb.el (btxdb:authors-display->list) (btxdb:rrfr): Use `delete-region'. 2006-06-08 Thien-Thi Nguyen * btxdb.el (btxdb-find-file): Use `db-find-file'. 2006-06-06 Thien-Thi Nguyen * btxdb.el (btxdb-find-file): Make `dbc-database' buffer-local. 2006-01-03 Thien-Thi Nguyen * btxdb.el (btxdb:extract-year, btxdb:match-years): Use `string-to-number'. 2005-12-31 Thien-Thi Nguyen * btxdb.el: Use `db-record-field' and/or `db-record-set-field'. 2005-12-30 Thien-Thi Nguyen * journals.dba (btxdb-update-journals): Use `db-maprecords'. 2005-12-06 Thien-Thi Nguyen * journals.dat: Rewrite in "format 0.7". 2005-11-27 Thien-Thi Nguyen * btxdb.el (btxdb:rrfr): Remove `(goto-char (point-min))'. 2005-11-24 Thien-Thi Nguyen * btxdb.el (journal, author): For these recordfieldtypes, arrange to remember the :actual->stored function in symbol property of `btxdb'. (btxdb:write-field): Use symbol property of `btxdb'. 2005-11-23 Thien-Thi Nguyen * btxdb.el (btxdb:rrfr): Return plist. 2005-11-19 Thien-Thi Nguyen * journals.dba (btxdb-update-journals): No longer specify DB to `maprecords'. 2005-11-19 Thien-Thi Nguyen * btxdb.el (btxdb:initialize): Fix bug: Use `dbf-format-name-spec-alist'. 2005-11-19 Thien-Thi Nguyen * btxdb.el (btxdb:fields): Use `defvar'. (btxdb:authors->list): Use `with-temp-buffer'. (btxdb:authors-display->list): Likewise. 2005-11-19 Thien-Thi Nguyen * btxdb.el (btxdb:set-format-from-data, btxdb:write-field) (btxdb:wrfr): No longer pass DATABASE to `record-field'. 2005-11-18 Thien-Thi Nguyen * btxdb.el (btxdb:rrfr): Use `db-make-record'. 2005-11-18 Thien-Thi Nguyen * btxdb.el (btxdb:write-field, btxdb:initialize): Update refs to `edb--v1-rs' slots. 2005-10-29 Thien-Thi Nguyen * journals.dba: No longer specify data file. 2005-10-29 Thien-Thi Nguyen * btxdb.el (btxdb:set-print-name): Delete func. * bibtex.fmt: No longer call `btxdb:set-print-name'. 2005-10-24 Thien-Thi Nguyen * journals.dba: No longer specify default format file. 2005-10-24 Thien-Thi Nguyen * btxdb.el (btxdb-find-file): Rename arg to FILENAME. 2005-10-15 Thien-Thi Nguyen * journals.dba, btxdb.el: Don't quote lambda forms. 2005-10-11 Thien-Thi Nguyen * btxdb.el (btxdb:build-journal-alists): Fix typo introduced 2005-01-18: Remove spurious reference to `locate-file'. 2005-10-04 Thien-Thi Nguyen * btxdb.el (btxdb:authors->list): Call `buffer-disable-undo' with no args. (btxdb:authors-display->list): Likewise. 2005-05-27 Thien-Thi Nguyen * gpl.texinfo: Delete file. * btxdb.texi (Copying): Replace @include w/ copyright notice. * Makefile (SUPPORT): Remove gpl.texinfo. (NON_CVS_FILES): Delete var. Remove references. 2005-05-27 Thien-Thi Nguyen * COPYING: Delete file; redundant w/ that in top-level dir. * Makefile (SUPPORT, NON_CVS_FILES): Remove COPYING. 2005-04-11 Thien-Thi Nguyen * btxdb.el (btxdb:initialize): Use `edb--copy-v1-rs'. 2005-01-19 Thien-Thi Nguyen * btxdb.el (btxdb:write-field): Pass key directly to `database-recordfieldspec'. (btxdb:initialize): Likewise. 2005-01-19 Thien-Thi Nguyen * btxdb.el: Remove "Local Variables" comment block. 2005-01-18 Thien-Thi Nguyen * btxdb.el (btxdb:build-journal-alists): Use `db-locate-readable-file-prefer-cwd'. (btxdb-find-file): Likewise. 2005-01-14 Thien-Thi Nguyen * btxdb.el, journals.dba: Use `setf' forms. 2004-10-08 Thien-Thi Nguyen * btxdb.el: Use `match-string' instead of `db-match-string'. * edbibtex/edbibtex.el: Likewise. 2004-09-13 Thien-Thi Nguyen * btxdb.el (btxdb:build-journal-alists): Use `locate-file'. (btxdb-find-file): Likewise. 2004-09-09 Thien-Thi Nguyen * btxdb.el (btxdb:write-field): Use `replace-regexp-in-string'. 2004-09-08 Thien-Thi Nguyen * btxdb.el (btxdb-find-file): Use `db-read-database-file'. 2004-09-03 Thien-Thi Nguyen * btxdb.el: Throughout, use new interface for `define-displaytype-from-displayspec' and `define-recordfieldtype-from-recordfieldspec'. 2004-08-28 Thien-Thi Nguyen * btxdb.el (btxdb:initialize): Use `database-set-fieldnames-to-list'. 2004-08-27 Thien-Thi Nguyen * btxdb.el (btxdb:write-field): Use `db-string-replace-regexp-2'. 2004-08-25 Thien-Thi Nguyen * btxdb.el: Update copyright. (btxdb:RCS-Id): Update. (btxdb:initialize): Use `add-hook'. Sat Nov 20 22:14:10 1993 Thorsten Ohl (ohl@linux) * README: describe brute force patch to EDB to make in run under Emacs 19. * btxdb.el: LCD Entry. * VERSION = 0.6 (There are no code changes, but the EDB patch is really necessary ...) Tue May 25 19:01:48 1993 Thorsten Ohl (ohl@chico) * VERSION = 0.5 * btxdb:RCS-Id: remove the $'s * btxdb:fields: NIL -> UNKNOWN * make CLASS an enumerated type * btxdb:rrfr: protect against bogus types Mon May 24 18:17:04 1993 Thorsten Ohl (ohl@chico) * Makefile: make INSTALL and NEWS from btxdb.info. Fri May 21 18:24:02 1993 Thorsten Ohl (ohl@chico) * make month an enumerated type. Much simpler to code and use. Thu May 20 18:45:28 1993 Thorsten Ohl (ohl@chico) * VERSION = 0.4 * all format files: double the backslashes. * btxdb:set-print-name: new function: use the file name as print name. * btxdb:set-format-from-data: don't use custom formats, iff btxdb:always-use-full-format is non nil. * btxdb:always-use-full-format: new variable, btxdb:toggle-full-format: new function. Thu May 20 13:51:57 1993 Thorsten Ohl (ohl@chico) * btxdb.el: exchange the third and fourth arguments of RECORD-SET-FIELD to bring btxdb up to EDB 1.15. Wed May 12 15:49:30 1993 Thorsten Ohl (ohl@chico) * btxdb:rrfr: initialize MONTH. Wed Mar 31 14:37:48 1993 Thorsten Ohl (ohl@chico) * Makefile: (EXPORT_FLAG) don't use the time to identify the version to export, this adds files from the Attic. Thu Jan 14 16:35:22 1993 Thorsten Ohl (ohl@chico) * btxdb:initialize: the last change was NOT a goot idea, because it broke using multiple databases. Temporarily protect `btxdb:setup-read-buffer' only. * *.fmt: don't have any required fields at all. Too confusing for the user. Thu Jan 14 15:54:52 1993 Thorsten Ohl (ohl@chico) * btxdb:initialize: protect against multiple invocations (this broke adding of a new record). * btxdb:help-info: hook for more extensive help. Wed Jan 13 20:52:07 1993 Thorsten Ohl (ohl@chico) * btxdb:fields: allow type specific ignored fields. * use this feature for errata of articles and techreports and for the ISBN of books, manuals, and proceedings. Mon Jan 11 17:48:50 1993 Thorsten Ohl (ohl@chico) * btxdb:journals-file-path: search here for `journals.el'. Mon Jan 11 16:30:40 1993 Thorsten Ohl (ohl@chico) * (btxdb-find-file): new function. Almost identical to (db-find-file), but provides a bibtex.fmt as default format. * BibTeX-db::* -> btxdb:* Cosmetical change. * added example directory. * Update VERSION to 0.2. Mon Jan 11 11:59:46 1993 Thorsten Ohl (ohl@chico) * Put the .dba file into a local variables section of bibtex.fmt (Michael Ernst's suggestion). Mon Jan 4 20:09:32 1993 Thorsten Ohl (ohl@chico) * btxdb.el (BibTeX-db::set-record-type): new function. * fix some missing defaults. Mon Jan 4 17:20:19 1993 Thorsten Ohl (ohl@chico) * journals.dat, journals.dba, journals.fmt, journals-full.rep, journals-abbrev.rep: new files, implementing a simple database for journal @string's. * Makefile: maintain them. * btxdb.el: new display type `journal' for minimal support of journal @string's. * article.fmt, bibtex.fmt: use \journal. Wed Dec 30 21:34:13 1992 Thorsten Ohl (ohl@chico) * Handle editors like authors. * Save the prolog in the BibTeX file. * Maintain an ``updated'' field. Wed Dec 30 18:34:10 1992 Thorsten Ohl (ohl@chico) * New display/record types for year, month, and author. * Rename general utility functions to `tho::...'. Fri Dec 25 21:53:10 1992 Thorsten Ohl (ohl@chico) * masterthesis -> mastersthesis (typo). * Almost usable prototype. ChangeLog,v 1.18 1993/11/20 22:22:53 ohl Exp edb-1.31/examples/btxdb/Makefile0000444000175000017500000000500410745370011014740 0ustar ttnttn# Makefile for btxdb # Makefile,v 1.18 1993/11/20 22:22:53 ohl Exp VERSION = 0.6 prefix = $(HOME) ELISP_DIR = $(prefix)/emacs INFO_DIR = $(prefix)/info FMT_DIR = $(prefix)/tex/bibtex/fmt INSTALL = install INSTALL_DATA = install -m 644 # Emacs Lisp byte-compiler. Make sure that it can find EDB. EMACS = emacs EFLAGS = -l default.el EC = $(EMACS) -batch $(EFLAGS) -f batch-byte-compile CVSTAG = BTXDB_`echo $(VERSION) | sed s/[.]/_/g` EXPORT_FLAG = -r $(CVSTAG) SUPPORT = README INSTALL NEWS Makefile TODO ChangeLog \ btxdb.texi btxdb.info examples/bibtex.bib ELISP_FILES = btxdb.el FMT_FILES = article.fmt bibtex.fmt book.fmt booklet.fmt conference.fmt \ inbook.fmt incollection.fmt inproceedings.fmt manual.fmt \ mastersthesis.fmt misc.fmt phdthesis.fmt proceedings.fmt \ techreport.fmt unpublished.fmt JOURNAL_FILES = journals.dat journals.dba journals.fmt \ journals-full.rep journals-abbrev.rep DIST_FILES = $(SUPPORT) $(ELISP_FILES) $(FMT_FILES) $(JOURNAL_FILES) DIST_DIR = btxdb-$(VERSION) TAR_FILE = btxdb-$(VERSION).tar.Z SHAR_FILE = btxdb-$(VERSION).shar TMP_FILE = /tmp/btxdb.tmp all: btxdb.elc journals.el btxdb.info btxdb.dvi install: btxdb.elc btxdb.info $(FMT_FILES) $(INSTALL_DATA) btxdb.elc $(ELISP_DIR) $(INSTALL_DATA) $(FMT_FILES) $(FMT_DIR) $(INSTALL_DATA) btxdb.info $(INFO_DIR) btxdb.elc: btxdb.el $(EC) btxdb.el INSTALL: btxdb.info cat -v btxdb.info | sed -n '/^Installation$$/,/^^_$$/p' \ | sed '$$d' > $@ NEWS: btxdb.info cat -v btxdb.info | sed -n '/^News$$/,/^^_$$/p' | sed '$$d' > $@ btxdb.info: btxdb.texi makeinfo btxdb.texi btxdb.dvi: btxdb.texi tex btxdb.texi texindex btxdb.cp btxdb.fn btxdb.ky btxdb.pg btxdb.tp btxdb.vr tex btxdb.texi tex btxdb.texi journals.el: journals.dat echo '(db-find-file "journals.dat") (btxdb-update-journals)' \ > $(TMP_FILE) emacs -batch $(EFLAGS) -l $(TMP_FILE) rm -fr $(TMP_FILE) clean: rm -f *~ *.cp *.fn *.ky *.pg *.tp *.vr *.cps *.fns *.kys *.pgs \ *.tps *.vrs *.dvi *.log *.aux *.toc veryclean: clean rm -f *.elc journals.el journals-full.bib journals-abbrev.bib \ btxdb.info $(TAR_FILE) $(SHAR_FILE) INSTALL NEWS commit: cvs commit -m 'freezing version $(VERSION)' cvs tag $(CVSTAG) tar: $(TAR_FILE) shar: $(SHAR_FILE) ftp: /home/ftp/pub/$(TAR_FILE) /home/ftp/pub/$(TAR_FILE): $(TAR_FILE) cp $(TAR_FILE) $@ $(TAR_FILE): $(DIST_FILES) rm -fr $(DIST_DIR) cvs export -d $(DIST_DIR) $(EXPORT_FLAG) btxdb tar cvf - $(DIST_DIR) | compress > $(TAR_FILE) rm -fr $(DIST_DIR) $(SHAR_FILE): $(DIST_FILES) shar -pX $(DIST_FILES) > $(SHAR_FILE) edb-1.31/examples/btxdb/README0000444000175000017500000000447710745370011014175 0ustar ttnttn[EDB-maintainer notes; original README follows pagebreak. to play: (require 'database) (add-to-list 'db-format-file-path default-directory) (load-file "btxdb.el") (btxdb-find-file "examples/bibtex.bib") second step is to enable finding *.fmt files, ymmv. --ttn 2006-06-10] This directory contains some hacked code which might become a BibTeX interface for the GNU Emacs Database (EDB) someday. Note: This version *requires* EDB Version 1.15 or later, since it uses the new argument order in RECORD-SET-FIELD. No promises, no warranty, no documentation ... ######################################################################## Emacs 19 has a `fixed' (i.e. POSIXLY_CORRECT) regex.c, which is exponentially slow for some cases. Unfortunately EDB's DISPLAYTYPE-REGEXP is one of those (this is a good chance to laern, what `exponentially slow' really means :-). If you do not use the abbreviated displayspecs without commata, you can apply the following patch to EDB: =================================================================== RCS file: /home/sources/ohl/emacs/edb/db-format.el,v retrieving revision 1.4 retrieving revision 1.5 diff -c -r1.4 -r1.5 *** 1.4 1993/11/20 18:31:04 --- 1.5 1993/11/20 21:14:44 *************** *** 388,394 **** ;; Perhaps the comma shouldn't be optional; but then I'd have to do special ;; work for the first field, which I'm loathe to do. ! (defconst displaytype-regexp (concat ",?" "\\(" symbol-regexp "\\|" displaytype-nonsymbol-regexp "\\)")) --- 388,397 ---- ;; Perhaps the comma shouldn't be optional; but then I'd have to do special ;; work for the first field, which I'm loathe to do. ! ;; [ Hmm, the optional comma is a desaster for the `fixed' regex.c of ! ;; Emacs 19. Since I do not use the display abbreviations, I ! ;; decided to make it mandatory. -tho ] ! (defconst displaytype-regexp (concat "," "\\(" symbol-regexp "\\|" displaytype-nonsymbol-regexp "\\)")) ######################################################################## /// Thorsten Ohl, TH Darmstadt, Schlossgartenstr. 9, D-64289 Darmstadt, Germany //////////////// net: ohl@crunch.ikp.physik.th-darmstadt.de, ohl@gnu.ai.mit.edu /// voice: +49-6151-16-3116, secretary: +49-6151-16-2072, fax: +49-6151-16-2421 README,v 1.3 1993/11/20 22:22:54 ohl Exp edb-1.31/examples/btxdb/TODO0000444000175000017500000000233710745370011013776 0ustar ttnttnTODO -- some of the things left to do in the BibTeX DataBase TODO,v 1.15 1993/05/21 22:30:02 ohl Exp * recover from broken entry types more gracefully. * Check that the problems with copying among multiple databases have really disappeared in EDB 1.15. * Fix the bug that makes EDB unusable on other files, after btxdb has been loaded. * Invoke btxdb:initialize less often. Currently it's called every time a new record is called, because bibtex.fmt is read then. * Work-around or fix the bug in EDB that breaks `M-x fill-paragraph'. * Make the `journal' displaytype better understandable for someone who hasn't read the code. Maybe even make an enumerated type. * Perform more consistency checks on the data after reading from file and after data-entry. * Minimal support for @STRING. * Test the parser and support a larger subset of the BibTeX syntax (though we will probably not support every brain-damaged ``feature''). * Maybe move from the completely flat model to something more sophisticated. * Provide hooks for the internal file format (speed). Local Variables: mode:indented-text auto-fill-hook:do-auto-fill End: edb-1.31/examples/btxdb/article.fmt0000444000175000017500000000200310745370011015427 0ustar ttnttn/////////////////////////////// ARTICLE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent Journal: \journal,journal Year: \year,nil-or-string ................................................................Optional Volume: \volume,nil-or-string Number: \number,nil-or-string Pages: \pages,nil-or-string Month: \month,month Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Errata: \errata,nil-or-string,indent Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ARTICLE //////////////////////////////// edb-1.31/examples/btxdb/bibtex.fmt0000444000175000017500000000330110745370011015263 0ustar ttnttn/////////////////////////////// UNKNOWN \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Class: \class,class Code: \tag,nil-or-string ................................................................Required ................................................................Optional Author: \author,author Editor: \editor,author Title: \title,nil-or-string,indent Journal: \journal,journal Month: \month,month Year: \year,nil-or-string Volume: \volume,nil-or-string Chapter: \chapter,nil-or-string,indent Number: \number,nil-or-string Pages: \pages,nil-or-string Publisher: \publisher,nil-or-string,indent Booktitle: \booktitle,nil-or-string,indent Series: \series,nil-or-string,indent Edition: \edition,nil-or-string School: \school,nil-or-string,indent Institution: \institution,nil-or-string,indent Organization: \organization,nil-or-string,indent Address: \address,nil-or-string,indent Type: \type,nil-or-string,indent Howpublished: \howpublished,nil-or-string,indent Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored ISBN: \isbn,nil-or-string LCNumber: \lcnum,nil-or-string Errata: \errata,nil-or-string,indent Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ UNKNOWN //////////////////////////////// Local Variables: eval: (require 'btxdb) eval: (btxdb:initialize) End: edb-1.31/examples/btxdb/book.fmt0000444000175000017500000000225110745370011014743 0ustar ttnttn///////////////////////////////// BOOK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Editor: \editor,author Title: \title,nil-or-string,indent Publisher: \publisher,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Volume: \volume,nil-or-string Number: \number,nil-or-string Series: \series,nil-or-string,indent Address: \address,nil-or-string,indent Edition: \edition,nil-or-string Month: \month,month Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored ISBN: \isbn,nil-or-string LCNumber: \lcnum,nil-or-string Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ BOOK ///////////////////////////////// edb-1.31/examples/btxdb/booklet.fmt0000444000175000017500000000165010745370011015452 0ustar ttnttn//////////////////////////////// BOOKLET \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Title: \title,nil-or-string,indent ................................................................Optional Author: \author,author Howpublished: \howpublished,nil-or-string,indent Address: \address,nil-or-string,indent Month: \month,month Year: \year,nil-or-string Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ BOOKLET /////////////////////////////// edb-1.31/examples/btxdb/btxdb.el0000444000175000017500000006545610745370011014746 0ustar ttnttn;; btxdb.el -- BibTeX Database running on top of EDB ;; Copyright (C) 2004,2005,2008 Thien-Thi Nguyen ;; ;; 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; LCD Archive Entry: ;; btxdb|Thorsten Ohl|ohl@crunch.ikp.physik.th-darmstadt.de ;; |BibTeX database program for Emacs; runs on top of EDB ;; |Nov 20, 1993|0.6|~/packages/btxdb.tar.gz| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defconst btxdb:RCS-Id (concat (substring "btxdb.el,v 1.23 1993/11/20 22:22:54 ohl Exp" 0 -8) " (plus maintenance by ttn)") "RCS identification string.") (require 'database) ;;; File names (defvar btxdb:journals-file-name "journals.el" "Name of a file containing the definition of `btxdb:journals'.") (defvar btxdb:journals-file-path '(".") "List of directories where to search for `btxdb:journals-file-name'.") ;;; Formatting (defvar btxdb:always-use-full-format nil "Iff this variable is not nil, btxdb will always use the full \(aka `unknown'\) format for display.") (defconst btxdb:ws "[ \t\n]*" "White Space.") (defvar btxdb:record-type-regexp "[A-Za-z]+" "Regular expression matching the record type. It must *not* contain grouping parentheses!") (defvar btxdb:record-tag-regexp "[^ \t\n,]+" "Regular expression matching the record tag. It must *not* contain grouping parentheses!") (defconst btxdb:right-record-delim-regexp "[})]" "Right delimiter for reading records. A useful (i.e. BibTeX compatible) value is `[})]'.") (defconst btxdb:left-record-delim-regexp "[{(]" "Right delimiter for reading records. A useful (i.e. BibTeX compatible) value is `[{(]'.") (defvar btxdb:left-record-delim-string "{" "Left delimiter for writing records. Useful (i.e. BibTeX compatible) values are `{' or `('.") (defvar btxdb:right-record-delim-string "}" "Right delimiter for writing records. Useful (i.e. BibTeX compatible) values are `}' or `)'.") (defconst btxdb:field-name-regexp "[^ \t\n=]+" "Regular expression matching the field name. It must *not* contain grouping parentheses!") (defvar btxdb:left-field-delim-string "{" "Left delimiter for writing values of fields. Useful (i.e. BibTeX compatible) values are `{' or `\"'.") (defvar btxdb:right-field-delim-string "}" "Right delimiter for writing values of fields. Useful (i.e. BibTeX compatible) values are `}' or `\"'.") ;;; Some list functions (defun tho:symbols->alist (symbols) (mapcar (lambda (field) (cons (symbol-name field) field)) symbols)) (defun tho:member (symbol list) "Returns T iff SYMBOL is a member of LIST, using EQUAL for comparison." (if (not list) nil (if (equal symbol (car list)) t (tho:member symbol (cdr list))))) (defun tho:merge-2lists (list1 list2) "Returns the unions of LIST1 and LIST2. Caveat: this is a naive and slow recursive implementation." (if (not list2) list1 (if (tho:member (car list2) list1) (tho:merge-2lists list1 (cdr list2)) (tho:merge-2lists (cons (car list2) list1) (cdr list2))))) (defun tho:merge-lists (lists) "Returns the unions of LISTS. Caveat: this is a naive and slow recursive implementation." (if (not (cdr lists)) (car lists) (tho:merge-lists (cons (tho:merge-2lists (car lists) (car (cdr lists))) (cdr (cdr lists)))))) (defun tho:subtract-lists (lista listb) "Remove all elements of LISTB from LISTA" (if (not (car lista)) nil (if (memq (car lista) listb) (tho:difference (cdr lista) listb) (cons (car lista) (tho:difference (cdr lista) listb))))) ;;; Other trivia (defun tho:not-nil-or-empty-stringp (obj) "Return NIL iff OBJ is NIL or an empty string. (Coded clumsily to be fast even if the compiler doesn't know about boolean shortcuts.)" (if obj (if (stringp obj) (not (string-equal obj "")) t) nil)) ;;; (defvar btxdb:fields ;; ;; Format: (... (class . (required optional ignored)) ...) ;; '((article . ((author title journal year) (volume number pages month note) (errata))) (book . ((author editor title publisher year) (volume number series address edition month note) (isbn lcnum))) (booklet . ((title) (author howpublished address month year note) ())) (conference . ((author title booktitle year) (editor volume number series pages address month organization publisher note) ())) (inbook . ((author editor title chapter pages publisher year) (volume number series type address edition month note) ())) (incollection . ((author title booktitle publisher year) (editor volume number series type chapter pages address edition month note) ())) (inproceedings . ((author title booktitle year) (editor volume number series pages address month organization publisher note) ())) (manual . ((title) (author organization address edition month year note) (isbn lcnum))) (mastersthesis . ((author title school year) (type address month note) ())) (misc . ((none) (author title howpublished month year note) ())) (phdthesis . ((author title school year) (type address month note) ())) (proceedings . ((title year) (editor volume number series address month organization publisher note) (isbn lcnum))) (techreport . ((author title institution year) (type number address month note) (errata))) (unpublished . ((author title note) (month year) ())) ;; This serves a dual purpose: catch errors and provide ;; fields beyond the BibTeX specs. (unknown . (() (key crossref) (annote keywords updated))))) (defun btxdb:required-fields (class) "Return the required fields in an entry of type CLASS." (nth 0 (cdr (assoc class btxdb:fields)))) (defun btxdb:optional-fields (class) "Return the optional fields in an entry of type CLASS." (nth 1 (cdr (assoc class btxdb:fields)))) (defun btxdb:ignored-fields (class) "Return the ignored (by BibTeX) fields in an entry of type CLASS." (nth 2 (cdr (assoc class btxdb:fields)))) (defun btxdb:useful-fields (class) "Return the useful fields in an entry of type CLASS." (tho:merge-lists (cdr (assoc class btxdb:fields)))) (defun btxdb:bogus-fields () "Return the useless nonempty fields in the current entry." (interactive) (tho:subtract-lists btxdb:field-names (btxdb:useful-fields (intern (dbf-displayed-record-field 'class))))) (setq btxdb:help-info '( (annote . "An annotation. It is not used by the standard bibliography styles, but may be used by others that produce an annotated bibliography.") (author . "The name(s) of the author(s), in the format described in the LaTeX book. However, instead of separating by \"and\" we keep them one per line.") (booktitle . "Title of a book, part of which is being cited. See the LaTeX book for how to type titles. For book entries, use the TITLE field instead.") (chapter . "A chapter (or section or whatever) number.") (crossref . "The database key of the entry being cross referenced.") (edition . "The edition of a book - for example, \"Second\". This should be an ordinal, and should have the first letter capitalized, as shown here; the standard styles convert to lower case when necessary.") (editor . "Name(s) of editor(s), typed as indicated in the LaTeX book. If there is also an `author' field, then the `editor' field gives the editor of the book or collection in which the reference appears.") (howpublished . "How something strange has been published. The first word should be capitalized.") (institution . "The sponsoring institution of a technical report.") (journal . "A journal name. Abbreviations are provided for many journals. The display format is either Journal: SYMBOL -> FULL-NAME (aka ABBREVIATED-NAME) or Journal: NAME Everything after the string \" -> \" will be ignored on input; this allows us use both symbolic and explicit names.") (key . "Used for alphabetizing, cross referencing, and creating a label when the `author' information, is missing. This field should not be confused with the key that appears in the `\cite' command and at the beginning of the database entry.") (month . "The month in which the work was published or, for an unpublished work, in which it was written. \(This is an enumerated type.\)") (note . "Any additional information that can help the reader. The first word should be capitalized.") (number . "The number of a journal, magazine, technical report, or of a work in a series. An issue of a journal or magazine is usually identified by its volume and number; the organization that issues a technical report usually gives it a number; and sometimes books are given numbers in a named series.") (organization . "The organization that sponsors a conference or that publishes a `manual'.") (pages . "One or more page numbers or range of numbers, such as `42--111' or `7,41,73--97' or `43+' (the `+' in this last example indicates pages following that don't form a simple range). To make it easier to maintain `Scribe'-compatible databases, the standard styles convert a single dash (as in `7-33') to the double dash used in TeX to denote number ranges (as in `7--33').") (publisher . "The publisher's name.") (school . "The name of the school where a thesis was written.") (series . "The name of a series or set of books. When citing an entire book, the `title' field gives its title and an optional `series' field gives the name of a series or multi-volume set in which the book is published.") (title . "The work's title, typed as explained in the LaTeX book.") (type . "The type of a technical report---for example, `Research Note'.") (volume . "The volume of a journal or multivolume book.") (year . "The year of publication or, for an unpublished work, the year it was written. Generally it should consist of four numerals, such as `1984', although the standard styles can handle any `year' whose last four nonpunctuation characters are numerals, such as `(about 1984)'.") (errata . "Known (or suspected) errors in this publication. Either a reference to published errata, or a short note explaining the error.") (isbn . "The ISBN Number(s) of this publication.") (lcnum . "The Library of Congress classification number of this publication. This is used by some other libraries also."))) (setq btxdb:all-fields (append (mapcar (lambda (pair) (append (car (cdr pair)) (car (cdr (cdr pair))) (car (cdr (cdr (cdr pair)))))) btxdb:fields))) (setq btxdb:field-names (sort (copy-sequence (tho:merge-lists btxdb:all-fields)) (lambda (s1 s2) (string-lessp (symbol-name s1) (symbol-name s2))))) (setq btxdb:field-name-alist (tho:symbols->alist btxdb:field-names)) (setq btxdb:alternate-format-names (mapcar (lambda (record) (let ((name (symbol-name (car record)))) ;;; use bibtex.fmt as generic format file (if (string= name "unknown") (cons "unknown" "bibtex.fmt") (cons name (concat name ".fmt"))))) btxdb:fields)) (defun btxdb:set-format-from-data (record) "Iff BTXDB:ALWAYS-USE-FULL-FORMAT is not nil, set the custom format. This will suceed, because we filter out bogus record types during the initial reading and the user can't enter invalid enumeration types." (db-change-format (if btxdb:always-use-full-format "unknown" (db-record-field record 'class)))) (defun btxdb:toggle-full-format (arg) "Toggle the use of custom formats. A prefix argument will force custom format." (interactive "P") (setq btxdb:always-use-full-format (or arg (not btxdb:always-use-full-format))) (if btxdb:always-use-full-format (message "Using `unknown' format exclusively.") (message "Using custom formats."))) (defun btxdb:note-update (&optional field old new) "Update the 'EDITED field in this record. Called automatically when any other field is updated." (dbf-this-record-set-field 'updated (let ((now (current-time-string))) (concat (substring now 4 10) ", " (substring now 20))))) (setq btxdb:record-type-alist (mapcar (lambda (record) (if (car record) (let ((name (symbol-name (car record)))) (cons name name)))) btxdb:fields)) (defun btxdb:set-record-type () "Change the type of the current record" (interactive) (let ((class (completing-read "New record type: " btxdb:record-type-alist nil t))) (dbf-displayed-record-set-field 'class class) (db-emergency-restore-format t))) (defun btxdb:validate-record () "" (interactive) (switch-to-buffer (get-buffer-create "*BibTeX-Warnings*")) (setq buffer-read-only nil) (insert-string "BTXDB:VALIDATE-RECORD is not implemented yet!\n") (setq buffer-read-only t)) ;;; This *almost* allows us to use M-q (fill-paragraph) on multi-line ;;; fields. But EDB insists on killing the last character ... (defun btxdb:set-fill-prefix (index) "" (let ((amt (dbf-this-field-indent))) (if amt (setq fill-prefix (make-string amt ? ))))) ;;; Datatype year (edb-define-displaytype 'year-short nil :indent nil :max-height 1 :actual->display 'btxdb:extract-year) (edb-define-recordfieldtype 'year nil :type 'nil-or-string :default-value "" :sort-fn 'btxdb:compare-years :match-function 'btxdb:match-years) (defun btxdb:extract-year (s) (if s (if (string-match "\\([0-9]+\\)[\\s.\\s)]*$" s) (substring s (match-beginning 1) (match-end 1)) "") "")) (defun btxdb:compare-years (y1 y2) (< (string-to-number (btxdb:extract-year y1)) (string-to-number (btxdb:extract-year y2)))) (defun btxdb:match-years (y1 y2) (= (string-to-number (btxdb:extract-year y1)) (string-to-number (btxdb:extract-year y2)))) ;;; Enumerated types: ;;; Datatype class (edb-define-enumtype 'class (mapcar (lambda (record) (symbol-name (car record))) btxdb:fields) nil) ;;; Datatype month (edb-define-enumtype 'month '(;internal/input /display /file ( 0 "unknown" "unknown" "") ( 1 "January" "January" "jan") ( 2 "February" "February" "feb") ( 3 "March" "March" "mar") ( 4 "April" "April" "apr") ( 5 "May" "May" "may") ( 6 "June" "June" "jun") ( 7 "July" "July" "jul") ( 8 "August" "August" "aug") ( 9 "September" "September" "sep") (10 "October" "October" "oct") (11 "November" "November" "nov") (11 "November" "November" "nov") (12 "December" "December" "dec")) nil) ;;; Datatype Author (edb-define-displaytype 'author nil :indent t :max-height nil :actual->display 'btxdb:authors-list->display :display->actual 'btxdb:authors-display->list) (edb-define-displaytype 'author-short nil :indent nil :max-height 1 :actual->display 'btxdb:authors-list->display-short) (edb-define-recordfieldtype 'author nil :type 'author :default-value nil :sort-fn 'btxdb:compare-authors :match-function 'btxdb:match-authors :actual->stored (put 'btxdb 'author 'btxdb:authors-list->string) :stored->actual 'btxdb:authors->list) (defun btxdb:authors->list (authors) (if (tho:not-nil-or-empty-stringp authors) (with-temp-buffer (save-excursion (insert authors)) (save-excursion (while (re-search-forward "[ \t\n]+" nil t) (replace-match " "))) (btxdb:authors->list-2 " and ")) nil)) (defun btxdb:authors-display->list (authors) (if (tho:not-nil-or-empty-stringp authors) (with-temp-buffer (save-excursion (insert authors)) (save-excursion (while (re-search-forward "[ \t]+" nil t) (replace-match " "))) (save-excursion (while (re-search-forward "[ \t]+$" nil t) (delete-region (match-beginning 0) (match-end 0)))) (btxdb:authors->list-2 "\n")) nil)) (defun btxdb:authors->list-2 (separator) (if (eq (point) (point-max)) nil (let* ((beginning (point)) (end (if (search-forward separator (point-max) 'move) (match-beginning 0) (point))) name) (save-excursion (goto-char end) (if (search-backward " " beginning t) (setq name (cons (buffer-substring (1+ (point)) end) (buffer-substring beginning (point)))) (setq name (cons (buffer-substring beginning end) "")))) (cons name (btxdb:authors->list-2 separator))))) (defun btxdb:authors-list->string (authors) (if authors (concat btxdb:left-field-delim-string (mapconcat (lambda (name) (if (string-equal (cdr name) "") (car name) (concat (cdr name) " " (car name)))) authors " and\n ") btxdb:right-field-delim-string) nil)) (defun btxdb:authors-list->display (authors) (mapconcat (lambda (name) (if (string-equal (cdr name) "") (car name) (concat (cdr name) " " (car name)))) authors "\n")) (defun btxdb:authors-list->display-short (authors) (mapconcat (lambda (name) (car name)) authors ", ")) (defun btxdb:compare-authors (a1 a2) "Compare the concatenated *last* names of the author lists A1 and A2." (string-lessp (mapconcat (lambda (name) (car name)) a1 "") (mapconcat (lambda (name) (car name)) a2 ""))) (defun btxdb:match-authors (pattern authors) (if (string-match (concat (cdr (car pattern)) " " (car (car pattern))) (concat (cdr (car authors)) " " (car (car authors)))) t (if (cdr authors) (btxdb:match-authors pattern (cdr authors)) nil))) ;;; Datatype journal (edb-define-displaytype 'journal nil :indent t :max-height nil :actual->display 'btxdb:journal->display :display->actual 'btxdb:display->journal) (edb-define-recordfieldtype 'journal nil :type 'journal :default-value nil :sort-fn 'btxdb:compare-journals :match-function 'btxdb:match-journals :actual->stored (put 'btxdb 'journal 'btxdb:journal->string) :stored->actual 'btxdb:string->journal) (defun btxdb:build-journal-alists () (let ((journals-file (db-locate-readable-file-prefer-cwd btxdb:journals-file-name btxdb:journals-file-path))) (if journals-file (load-file journals-file) (setq btxdb:journals nil))) (setq btxdb:journal-symbol-alist (mapcar (lambda (j) (list (aref j 0) (aref j 1) (aref j 2))) btxdb:journals)) (setq btxdb:journal-full-alist (mapcar (lambda (j) (list (aref j 1) (aref j 0) (aref j 2))) btxdb:journals)) (setq btxdb:journal-abbrev-alist (mapcar (lambda (j) (list (aref j 2) (aref j 0) (aref j 1))) btxdb:journals))) ;;; This is a minimalistic implementation, we could/should perform ;;; much better consistency checking here. (defun btxdb:journal->display (j) (if j (let ((expansion (assoc j btxdb:journal-symbol-alist))) (if expansion (concat j " -> " (car (cdr expansion)) " (aka " (car (cdr (cdr expansion))) ")") j)) "")) (defun btxdb:display->journal (j) (if (string-match " -> " j) (substring j 0 (match-beginning 0)) j)) (defun btxdb:journal->string (j) (if (tho:not-nil-or-empty-stringp j) (if (assoc j btxdb:journal-symbol-alist) j (concat btxdb:left-field-delim-string j btxdb:right-field-delim-string)) nil)) (defun btxdb:string->journal (j) j) ;;; I/O functions. ;;; Input (setq btxdb:syntax-table nil) (defun btxdb:setup-read-buffer () "Setup the sytax table etc. in the read buffer." (save-excursion (set-buffer db-buffer) (if (not btxdb:syntax-table) (setq btxdb:syntax-table (copy-syntax-table))) (set-syntax-table btxdb:syntax-table) (modify-syntax-entry ?{ "(}") (modify-syntax-entry ?} ")") (modify-syntax-entry ?( ".") (modify-syntax-entry ?) ".") (modify-syntax-entry ?[ ".") (modify-syntax-entry ?] "."))) (setq btxdb:comments-alist nil) (defun btxdb:read-comments () (save-excursion (set-buffer db-buffer) (goto-char (point-min)) (if (search-forward "@" nil t) (setf (sepinfo-pre-first-string (database-record-sepinfo database)) (buffer-substring (point-min) (point))))) ;; Clean up. (remove-hook 'db-before-read-hooks 'btxdb:read-comments)) (defun btxdb:rrfr () "Parse a BibTeX record." ;; canonicalize whitespace (save-excursion (while (re-search-forward "^[ \t\n]+\\|[ \t\n]+$" nil t) (delete-region (match-beginning 0) (match-end 0)))) (if (re-search-forward (concat "\\(" btxdb:record-type-regexp "\\)" btxdb:ws btxdb:left-record-delim-regexp btxdb:ws "\\(" btxdb:record-tag-regexp "\\)" btxdb:ws ",") nil t) (let ((class (downcase (match-string 1))) (tag (match-string 2)) plist) (flet ((plpush (f v) (setq plist (plist-put plist f v)))) ;; don't allow bogus entry types which will screw up our ;; format file search later. (plpush 'class (if (assoc class btxdb:alternate-format-names) class (db-warning "Entry type \"%s\" not recognized by BibTeX!" (match-string 1)) "unknown")) (plpush 'tag tag) (plpush 'month 0) (while (re-search-forward (concat "\\(" btxdb:field-name-regexp "\\)" btxdb:ws "=" btxdb:ws) nil t) (let ((key (cdr (assoc (downcase (match-string 1)) btxdb:field-name-alist))) (beg (point))) (forward-sexp) (if key (plpush key (if (or (equal ?{ (char-after beg)) (equal ?\" (char-after beg))) (buffer-substring (1+ beg) (1- (point))) (buffer-substring beg (point))))))) plist)) (error "Illformed record!"))) (defun btxdb:stored->actual () (database-stored->actual) ;; Clean up. (remove-hook 'db-after-read-hooks 'btxdb:stored->actual)) ;;; Output (defun btxdb:write-field (field) "Write a field in a BibTeX record, including a leading field separator. FIELD is a cons cell FIELDNAME . FIELDKEY." (let* ((name (car field)) (key (cdr field)) (val (db-record-field record key)) (a->s (get 'btxdb key))) (if a->s (setq val (funcall a->s val))) (if (tho:not-nil-or-empty-stringp val) (if a->s (insert ",\n " name "=" val) (insert ",\n " name "=" btxdb:left-field-delim-string (replace-regexp-in-string "\n" "\n " val) btxdb:right-field-delim-string))))) (defun btxdb:wrfr (record) "Write a BibTeX record." (insert (db-record-field record 'class) btxdb:left-record-delim-string (db-record-field record 'tag)) (mapcar 'btxdb:write-field btxdb:field-name-alist) (insert btxdb:right-record-delim-string "\n")) ;;; Interface to EDB (setq btxdb:initializedp nil) (defun btxdb:initialize () "Initialize the BibTeX subsystem for EDB." (database-set-fieldnames-to-list database (append '((class . class) tag) (mapcar (lambda (key) (cond ((memq key '(year month journal author)) (cons key key)) ((eq key 'editor) (cons 'editor 'author)) (t key))) btxdb:field-names)) 'string-or-nil) ;; Install field-specific help strings. (let (help) (mapc (lambda (field) (when (setq help (cdr (assq field btxdb:help-info))) (db-set-field-help database field help))) btxdb:field-names)) (dbf-set-summary-format (concat "[\\tag,string-or-nil,width=8] \\author,author-short,width=20 /" "/ \\title,string-or-nil,width=34 (\\year,year-short)")) (setq dbf-format-name-spec-alist btxdb:alternate-format-names) (setq dbf-before-display-record-function 'btxdb:set-format-from-data) (setq dbf-first-change-function 'btxdb:note-update) (setq dbf-enter-field-function 'btxdb:set-fill-prefix) (setf (database-read-record-from-region database) 'btxdb:rrfr (database-write-region-from-record database) 'btxdb:wrfr) (add-hook 'db-before-read-hooks 'btxdb:read-comments) (add-hook 'db-after-read-hooks 'btxdb:stored->actual) (let ((si (database-record-sepinfo database))) (setf (sepinfo-pre-first-string si) "" (sepinfo-pre-first-regexp si) "[^@]*@" (sepinfo-pre-first-regexp-submatch si) 0 (sepinfo-sep-string si) "\n@" (sepinfo-post-last-string si) (concat "\n# End of File," " written by\n# " btxdb:RCS-Id "\n") (sepinfo-post-last-regexp si) "\n+" (sepinfo-post-last-regexp-submatch si) 0)) (btxdb:build-journal-alists) (if (boundp 'db-buffer) (btxdb:setup-read-buffer)) (define-key database-view-mode-map "\C-xt" 'btxdb:set-record-type) (define-key database-edit-mode-map "\C-xt" 'btxdb:set-record-type) (define-key database-view-mode-map "\C-xv" 'btxdb:toggle-full-format) (define-key database-edit-mode-map "\C-xv" 'btxdb:toggle-full-format) (setq btxdb:initializedp t)) (defun btxdb-find-file (filename) "Read a .bib database from FILENAME; run EDB on it." (interactive "fBibTeX Database file: \n") (db-find-file filename "bibtex.fmt")) (provide 'btxdb) ;;; btxdb.el ends here edb-1.31/examples/btxdb/btxdb.texi0000444000175000017500000001265410745370011015307 0ustar ttnttn\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename btxdb.info @settitle Btxdb User's Manual @finalout @setchapternewpage odd @c %**end of header @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ifinfo This file documents the @code{btxdb} BibTeX Database system. Copyright (C) 1993 Thorsten Ohl Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Foundation. @end ifinfo @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @titlepage @title Btxdb @subtitle The BibTeX Database System @subtitle Edition 0.0, for btxdb Version 0.2 @subtitle January 1993 @author by Thorsten Ohl @page @vskip 0pt plus 1filll Copyright @copyright{} 1993 Thorsten Ohl Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Foundation. @end titlepage @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @node Top, , , (dir) @ifinfo This file documents the @code{btxdb} BibTeX Database System. @end ifinfo This documentation does not yet exist ... obviously. @menu * Copying:: Reading your rights. * Overview:: Preliminary information. * News:: Recent improvements. * Installation:: Installation. * Problems:: Reporting bugs. * Concept Index:: Index of concepts. @end menu @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @node Copying, Overview, Top, Top 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @node Overview, News, Copying, Top @chapter Overview @cindex overview @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @node News, Installation, Overview, Top @chapter News @itemize @bullet @item User visible changes from 0.4 to 0.5: @itemize @minus @item The entry type is now an enumerated type. Using the full format (toggled by @kbd{C-x v}) should now eliminate all errors when changing the entry type. @end itemize @item User visible changes from 0.3 to 0.4: @itemize @minus @item @samp{btxdb} is no longer compatible with @samp{EDB} Versions before 1.15. You will have to upgrade immediately. @item New command @kbd{C-x v} (aka.: @kbd{M-x btxdb:toggle-full-format}) to toggle the use of the full @samp{unknown} format. This is mainly useful for cleaning up entries. @end itemize @item User visible changes before 0.3: @itemize @minus @item Too many and forgotten ... @end itemize @end itemize @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @node Installation, Problems, News, Top @chapter Installation Here is how I recompile @samp{EDB} (Michael's @kbd{M-x byte-compile-database} never worked properly for me because some macros were not properly expanded). @example #!/bin/sh EMACSLOADPATH=.:$EMACSLOADPATH \ emacs -batch `for i in util*.el [bd]*.el; do echo -l $i; done` \ -f batch-byte-compile util*.el [bd]*.el @end example @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @node Problems, Concept Index, Installation, Top @chapter Reporting Bugs @cindex bugs @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @node Concept Index, , Problems, Top @unnumbered Concept Index @printindex cp @shortcontents @contents @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @bye edb-1.31/examples/btxdb/conference.fmt0000444000175000017500000000227310745370011016124 0ustar ttnttn////////////////////////////// CONFERENCE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent Booktitle: \booktitle,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Editor: \editor,author Volume: \volume,nil-or-string Number: \number,nil-or-string Series: \series,nil-or-string,indent Pages: \pages,nil-or-string Address: \address,nil-or-string,indent Month: \month,month Organization: \organization,nil-or-string,indent Publisher: \publisher,nil-or-string,indent Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ CONFERENCE ////////////////////////////// edb-1.31/examples/btxdb/examples/0000755000175000017500000000000011005377327015130 5ustar ttnttnedb-1.31/examples/btxdb/examples/bibtex.bib0000644000175000017500000000365510745370011017065 0ustar ttnttn# bibtex.bib,v 1.5 1993/05/25 23:13:51 ohl Exp # Effective Theories: @article{Pol84, author={J. Polchinski}, journal=np, pages={269}, updated={May 25, 1993}, volume={B231}, year={1984}} @techreport{Pol92, annote={TASI 1992 Lectures}, author={J. Polchinski}, number={NSF-ITP-92-132, UTTG-20-92}, title={Effective Field Theory and the Fermi Surface}, type={Preprint}, updated={Jan 21, 1993}, year={1992}} @article{Wei79, author={Steven Weinberg}, journal={Physica}, pages={327}, title={Phenomenological Lagrangians}, volume={96A}, year={1979}} @article{MG84, author={Aneesh Manohar and Howard Georgi}, journal=np, pages={189}, title={Chiral Quarks and the Non-Relativistic Quark Model}, updated={Jan 4, 1993}, volume={B234}, year={1984}} @article{GR86, author={Howard Georgi and Lisa Randall}, journal=np, pages={241}, title={Flavor Conserving {$CP$} Violation in Invisible Axion Models}, updated={May 25, 1993}, volume={B276}, year={1986}} @techreport{Geo92.7, author={Howard Georgi}, institution={Harvard University}, month=jul, number={HUTP/92-A036}, title={Generalized Dimensional Analysis}, type={Preprint}, updated={Jan 21, 1993}, year={1992}} @techreport{Geo92.9, author={Howard Georgi}, institution={Harvard University}, month=sep, number={HUTP/92-A049}, title={{$D$-$\bar D$} Mixing in Heavy Quark Effective Field Theory}, type={Preprint}, updated={Jan 21, 1993}, year={1992}} @techreport{ORS92, address={Cambridge, MA 02138}, author={Thorsten Ohl and Giulia Ricciardi and Elisabeth Simmons}, errata={No errors have been found .... yet}, institution={Harvard University}, month=dec, number={HUTP/92-A053}, title={{$D$-$\bar D$} Mixing in Heavy Quark Effective Field Theory: The Sequel}, type={Preprint}, updated={May 20, 1993}, year={1992}} # End of File, written by # btxdb.el,v 1.20 1993/05/21 22:30:06 edb-1.31/examples/btxdb/inbook.fmt0000444000175000017500000000233310745370011015273 0ustar ttnttn//////////////////////////////// INBOOK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Editor: \editor,author Title: \title,nil-or-string,indent Chapter: \chapter,nil-or-string,indent Pages: \pages,nil-or-string Publisher: \publisher,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Volume: \volume,nil-or-string Number: \number,nil-or-string Series: \series,nil-or-string,indent Type: \type,nil-or-string,indent Address: \address,nil-or-string,indent Edition: \edition,nil-or-string Month: \month,month Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ INBOOK //////////////////////////////// edb-1.31/examples/btxdb/incollection.fmt0000444000175000017500000000240410745370011016473 0ustar ttnttn///////////////////////////// INCOLLECTION \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent Booktitle: \booktitle,nil-or-string,indent Publisher: \publisher,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Editor: \editor,author Volume: \volume,nil-or-string Number: \number,nil-or-string Series: \series,nil-or-string,indent Type: \type,nil-or-string,indent Chapter: \chapter,nil-or-string,indent Pages: \pages,nil-or-string Address: \address,nil-or-string,indent Edition: \edition,nil-or-string Month: \month,month Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ INCOLLECTION ///////////////////////////// edb-1.31/examples/btxdb/inproceedings.fmt0000444000175000017500000000227010745370011016643 0ustar ttnttn//////////////////////////// INPROCEEDINGS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent Booktitle: \booktitle,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Editor: \editor,author Volume: \volume,nil-or-string Number: \number,nil-or-string Series: \series,nil-or-string,indent Pages: \pages,nil-or-string Address: \address,nil-or-string,indent Month: \month,month Organization: \organization,nil-or-string,indent Publisher: \publisher,nil-or-string,indent Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ INPROCEEDINGS ///////////////////////////// edb-1.31/examples/btxdb/journals-abbrev.rep0000444000175000017500000000003310745370011017101 0ustar ttnttn@string{\symbol={\abbrev}} edb-1.31/examples/btxdb/journals-full.rep0000444000175000017500000000003110745370011016600 0ustar ttnttn@string{\symbol={\full}} edb-1.31/examples/btxdb/journals.dat0000644000175000017500000000167110745370011015637 0ustar ttnttn;; Database file written by EDB; format 0.7 ["BibTeX Journal Name Database" [symbol full abbrev] [string string string] nil [nil nil nil "\n" nil nil nil nil nil nil] [nil nil nil " " nil nil nil nil nil nil] nil nil " " "\n" nil nil] ((:format-file . "journals.fmt")) ["cmc" "Communications in Mathematical Physics" "Comm.~Math.~Phys."] ["cpc" "Computer Physics Communications" "Comp.~Phys.~Comm."] ["np" "Nuclear Physics" "Nucl.~Phys"] ["npbproc" "Nuclear Physics B (Proceedings Supplement)" "Nucl.~Phys.~B (Proc.~Suppl.)"] ["pl" "Physics Letters" "Phys.~Lett."] ["prep" "Physics Reports" "Phys.~Rep."] ["pr" "Physical Review" "Phys.~Rev."] ["prl" "Physical Review Letters" "Phys.~Rev.~Lett."] ["sjnp" "Soviet Journal of Nuclear Physics" "Sov.~J.~Nucl.~Phys."] ["zp" "Zeitschrift f.~Physik" "Z. Phys."] ["zpa" "Zeitschrift f.~Physik A --- Hadrons and Nuclei" "Z.~Phys.~A"] ["zpc" "Zeitschrift f.~Physik C --- Particles and Fields" "Z.~Phys.~C"] edb-1.31/examples/btxdb/journals.dba0000444000175000017500000000347710745370011015621 0ustar ttnttn;; journals.dba -- BibTeX Journal strings ;; journals.dba,v 1.3 1993/01/11 21:44:06 ohl Exp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (setf db-use-internal-rep-p t (database-print-name database) "BibTeX Journal Name Database") (database-set-fieldnames-to-list database '(symbol full abbrev)) (dbf-set-summary-format "[\\symbol,string-or-nil,width=8] \\full,string-or-nil (aka \\abbrev)") (defun btxdb-update-journals () "" (interactive) (let ((fn (database-file dbc-database))) (mapcar (lambda (suffix) (save-excursion (db-report (concat "journals-" suffix ".rep")) (goto-char (point-min)) (insert "# journals-" suffix ".bib -- DO NOT EDIT!\n" "# created from " fn "\n" "# on " (current-time-string) ", edit this file instead.\n") (goto-char (point-max)) (insert "# The End.\n") (write-file (concat "journals-" suffix ".bib")))) '("full" "abbrev")) ;; EDB doesn't seem to be fully reentrant. Using EDB to read the ;; journals file while initializing another database loses. As a ;; kludge, we provide a separate file. (save-excursion (get-buffer-create "*Database Report*") (setq buffer-read-only nil) (erase-buffer) (emacs-lisp-mode) (insert ";;; journals.el -- DO NOT EDIT!\n" ";;; created from " fn "\n" ";;; on " (current-time-string) ", edit this file instead.\n") (insert "(setq btxdb:journals '(\n") (db-maprecords (lambda (r) (insert (format " %s\n" r)))) (insert "))\n;;; The End.\n") (write-file "journals.el")))) ;; Local Variables: ;; mode:emacs-lisp ;; End: edb-1.31/examples/btxdb/journals.fmt0000444000175000017500000000010010745370011015635 0ustar ttnttn Symbol: \symbol Full Name: \full Abbreviation: \abbrev edb-1.31/examples/btxdb/manual.fmt0000444000175000017500000000202610745370011015266 0ustar ttnttn//////////////////////////////// MANUAL \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Title: \title,nil-or-string,indent ................................................................Optional Author: \author,author Organization: \organization,nil-or-string,indent Address: \address,nil-or-string,indent Edition: \edition,nil-or-string Month: \month,month Year: \year,nil-or-string Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored ISBN: \isbn,nil-or-string LCNumber: \lcnum,nil-or-string Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ MANUAL //////////////////////////////// edb-1.31/examples/btxdb/mastersthesis.fmt0000444000175000017500000000170710745370011016714 0ustar ttnttn///////////////////////////// MASTERTHESIS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent School: \school,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Type: \type,nil-or-string,indent Address: \address,nil-or-string,indent Month: \month,month Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ MASTERTHESIS ///////////////////////////// edb-1.31/examples/btxdb/misc.fmt0000444000175000017500000000157610745370011014755 0ustar ttnttn///////////////////////////////// MISC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required ................................................................Optional Author: \author,author Title: \title,nil-or-string,indent Howpublished: \howpublished,nil-or-string,indent Month: \month,month Year: \year,nil-or-string Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ MISC ///////////////////////////////// edb-1.31/examples/btxdb/phdthesis.fmt0000444000175000017500000000171210745370011016005 0ustar ttnttn/////////////////////////////// PHDTHESIS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent School: \school,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Type: \type,nil-or-string,indent Address: \address,nil-or-string,indent Month: \month,month Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ PHDTHESIS ////////////////////////////// edb-1.31/examples/btxdb/proceedings.fmt0000444000175000017500000000222010745370011016307 0ustar ttnttn////////////////////////////// PROCEEDINGS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Title: \title,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Editor: \editor,author Volume: \volume,nil-or-string Number: \number,nil-or-string Series: \series,nil-or-string,indent Address: \address,nil-or-string,indent Month: \month,month Organization: \organization,nil-or-string,indent Publisher: \publisher,nil-or-string,indent Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored ISBN: \isbn,nil-or-string LCNumber: \lcnum,nil-or-string Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ PROCEEDINGS ///////////////////////////// edb-1.31/examples/btxdb/techreport.fmt0000444000175000017500000000203710745370011016172 0ustar ttnttn////////////////////////////// TECHREPORT \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent Institution: \institution,nil-or-string,indent Year: \year,nil-or-string ................................................................Optional Type: \type,nil-or-string,indent Number: \number,nil-or-string Address: \address,nil-or-string,indent Month: \month,month Note: \note,nil-or-string,indent Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Errata: \errata,nil-or-string,indent Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ TECHREPORT ////////////////////////////// edb-1.31/examples/btxdb/unpublished.fmt0000444000175000017500000000150510745370011016334 0ustar ttnttn////////////////////////////// UNPUBLISHED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Code: \tag,nil-or-string ................................................................Required Author: \author,author Title: \title,nil-or-string,indent Note: \note,nil-or-string,indent ................................................................Optional Month: \month,month Year: \year,nil-or-string Key: \key,nil-or-string Crossref: \crossref,nil-or-string .................................................................Ignored Keywords: \keywords,nil-or-string,indent Remarks: \annote,nil-or-string,indent Updated: \updated,nil-or-string \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ UNPUBLISHED ///////////////////////////// edb-1.31/examples/edbibtex/0000755000175000017500000000000011016452347013773 5ustar ttnttnedb-1.31/examples/edbibtex/Makefile0000444000175000017500000000307210745370011015426 0ustar ttnttn# Makefile for edbibtex 0.4 # The basename of your bibliographic database BASENAME = bibliography # The directory that contains your bibliographic database BIBDIR = /home/mike/txt/water # The directory in which you would like edbibtex to be installed BASEDIR = /usr/lib/emacs/site-lisp # The directory in which you would like your format files to be installed FORMATDIR = $(BASEDIR)/formats # The directory in which you would like your documentation to be installed INFODIR = /usr/info ############################################################## # You probably won't want to change anything after this line # ############################################################## FORMATS = article.fmt bibtex.fmt book.fmt booklet.fmt \ inbook.fmt incollection.fmt inproceedings.fmt manual.fmt \ mastersthesis.fmt misc.fmt phdthesis.fmt preamble.fmt proceedings.fmt \ string.fmt techreport.fmt unpublished.fmt DOCUMENTATION = edbibtex.texinfo CODE = edbibtex.el bibtex.dba compile.el Makefile ALL = $(FORMATS) $(DOCUMENTATION) $(CODE) all : edbibtex.elc edbibtex.info install : cp bibtex.fmt $(FORMATDIR)/$(BASENAME).fmt mv $(FORMATS) $(FORMATDIR) mv edbibtex.info $(INFODIR) cp bibtex.dba $(BIBDIR)/$(BASENAME).dba mv edbibtex.elc bibtex.dba $(BASEDIR) clean : rm $(ALL) edbibtex.elc : edbibtex.el emacs -batch -l compile.el edbibtex.info : edbibtex.texinfo makeinfo edbibtex.texinfo edbibtex.tgz : $(ALL) tar -cvzf edbibtex.tgz --directory .. \ --exclude RCS --exclude junk edbibtex edbibtex.uue : edbibtex.tgz uuencode edbibtex.tgz edbibtex.tgz > edbibtex.uue edb-1.31/examples/edbibtex/article.fmt0000444000175000017500000000217310745370011016122 0ustar ttnttn******************************* ARTICLE ******************************** Code: \BibTeX-tag ................................................................Required Author: \author Title: \title Journal: \journal Year: \year ................................................................Optional Volume: \volume Number: \number Pages: \pages Month: \month Note: \note .................................................................Ignored Editor: \editor Series: \series Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition School: \school Institution: \institution Organization: \organization Address: \address Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ******************************* ARTICLE ******************************** edb-1.31/examples/edbibtex/bibtex.dba0000444000175000017500000000450610745370011015716 0ustar ttnttn;; This is version 0.4 of BibTeX.dba. ;; Copyright (C) 1995, Michael Burschik. ;; For documentation please see the file `edbibtex.texinfo', which ;; you should have got along with this one. ;; This file is intended to be used with GNU Emacs. ;; 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 3 ;; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ;; Require the necessary package (i.e. "edbibtex.el") (require 'edbibtex) ;;;;;;;;;;;;;;;;;;;;;;; ;; Edbibtex Features ;; ;;;;;;;;;;;;;;;;;;;;;;; ;; turn string expansion off (setq BibTeX-expand-strings nil) ;; turn entry type dependent format selection on (setq BibTeX-multiple-format t) ;; set the default format (change its name here, if you would ;; like to rename the default format file) (setq BibTeX-default-format '("generic" . "bibtex.fmt")) ;; turn automatic default format selection on (setq BibTeX-use-default-format t) ;;;;;;;;;;;;;;;;;; ;; EDB Features ;; ;;;;;;;;;;;;;;;;;; ;; Fieldnames (database-set-fieldnames-to-list database (append BibTeX-special-fields BibTeX-fields)) (setf ;; Separating (sepinfo-sep-function (database-record-sepinfo database)) 'BibTeX-delimit-record ;; Reading (database-read-record-from-region database) 'BibTeX-rrfr ;; Writing (database-write-region-from-record database) 'BibTeX-wrfr) ;; Display (setq dbf-before-display-record-function 'BibTeX-set-format-from-data) (if (string< "1.18" edb-version) (setq dbf-format-name-spec-alist BibTeX-alternate-formats) (setq dbf-alternate-format-names BibTeX-alternate-formats)) ;; Changing (setq dbf-after-record-change-function 'BibTeX-validate-displayed-record) (add-hook 'db-before-read-hooks 'BibTeX-set-up-db-buffer) ;; Local variables: ;; mode: emacs-lisp ;; End: edb-1.31/examples/edbibtex/bibtex.fmt0000444000175000017500000000232110745370011015747 0ustar ttnttn******************************* UNKNOWN ******************************** Class: \BibTeX-entry-type Code: \BibTeX-tag ................................................................Required ................................................................Optional .................................................................Ignored Author: \author Editor: \editor Title: \title Journal: \journal Series: \series Year: \year Month: \month Volume: \volume Number: \number Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition School: \school Institution: \institution Organization: \organization Address: \address Type: \type Howpublished: \howpublished Note: \note Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ******************************* UNKNOWN ******************************** Local variables: eval: (load-file "bibtex.dba") End:edb-1.31/examples/edbibtex/book.fmt0000444000175000017500000000217310745370011015431 0ustar ttnttn********************************* BOOK ********************************* Code: \BibTeX-tag ................................................................Required Author: \author Editor: \editor Title: \title Year: \year Publisher: \publisher ................................................................Optional Volume: \volume Series: \series Address: \address Edition: \edition Month: \month Note: \note .................................................................Ignored Journal: \journal Number: \number Pages: \pages Chapter: \chapter Booktitle: \booktitle School: \school Institution: \institution Organization: \organization Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ********************************* BOOK ********************************* edb-1.31/examples/edbibtex/booklet.fmt0000444000175000017500000000217310745370011016136 0ustar ttnttn******************************* BOOKLET ******************************** Code: \BibTeX-tag ................................................................Required Title: \title ................................................................Optional Author: \author Howpublished: \howpublished Address: \address Month: \month Year: \year Note: \note .................................................................Ignored Editor: \editor Journal: \journal Series: \series Volume: \volume Number: \number Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition School: \school Institution: \institution Organization: \organization Type: \type Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ******************************* BOOKLET ******************************** edb-1.31/examples/edbibtex/compile.el0000444000175000017500000000043010745370011015733 0ustar ttnttn;; Load and compile edbibtex version 0.4 ;; These only serve to avoid compilation warnings. (defvar db-buffer nil) (defvar database nil) (defvar BibTeX-syntax-table (make-syntax-table)) ;; Now do some real work: (load-file "edbibtex.el") (byte-compile-file "edbibtex.el")edb-1.31/examples/edbibtex/edbibtex.el0000444000175000017500000004655710745370011016115 0ustar ttnttn;; $Id$ ;; LCD Archive Entry: ;; edbibtex|Michael Burschik|burschik@uni-bonn.de| ;; A BibTeX interface for Michael Ernst's Emacs Database.| ;; $Date$|0.4| ;; This file can be folded Origami style with Jamie Lokier's "folding.el". ;;{{{ File Header ;; Copyright (C) 1995, Michael Burschik. ;; This file is intended to be used with GNU Emacs. ;; 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 3 ;; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ;;}}} (require 'database) ;;{{{ Constants and Variables ;;{{{ Edbibtex version ;; self-explanatory (defconst edbibtex-version "0.4") ;;}}} ;;{{{ bibtex-mode-syntax-table ;; Define this here, so we don't have to require bibtex. (defvar bibtex-mode-syntax-table (eval-when-compile (let ((st (make-syntax-table))) (modify-syntax-entry ?\" "\"" st) (modify-syntax-entry ?$ "$$ " st) (modify-syntax-entry ?% "< " st) (modify-syntax-entry ?' "w " st) (modify-syntax-entry ?@ "w " st) (modify-syntax-entry ?\\ "\\" st) (modify-syntax-entry ?\f "> " st) (modify-syntax-entry ?\n "> " st) (modify-syntax-entry ?~ " " st) st))) ;;}}} ;;{{{ BibTeX-entry-type-alist ;; This alist is used to find the correct format file and to check and ;; validate entry types. (defconst BibTeX-entry-type-alist '(("article" "article.fmt" (author title journal year)) ("book" "book.fmt" ((xor author editor) title publisher year)) ("booklet" "booklet.fmt" (title)) ("conference" "inproceedings.fmt" (author title booktitle year)) ("generic" "bibtex.fmt" nil) ("inbook" "inbook.fmt" ((xor author editor) title (or chapter pages))) ("incollection" "incollection.fmt" (author title booktitle publisher year)) ("inproceedings" "inproceedings.fmt" (author title booktitle year)) ("manual" "manual.fmt" (title)) ("mastersthesis" "mastersthesis.fmt" (author title school year)) ("misc" "misc.fmt" nil) ("phdthesis" "phdthesis.fmt" (author title school year)) ("preamble" "preamble.fmt" (BibTeX-val)) ("proceedings" "proceedings.fmt" (title year)) ("string" "string.fmt" (BibTeX-var BibTeX-val)) ("techreport" "techreport.fmt" (author title institution year)) ("unpublished" "unpublished.fmt" (author title note))) "This constant contains a list of valid BibTeX entry types, their required fields and of format files associated with them.") ;;}}} ;;{{{ BibTeX-field-alist (defconst BibTeX-field-alist '(("address" . address) ("annote" . annote) ("author" . author) ("booktitle" . booktitle) ("chapter" . chapter) ("crossref" . crossref) ("edition" . edition) ("editor" . editor) ("howpublished" . howpublished) ("institution" . institution) ("journal" . journal) ("key" . key) ("month" . month) ("note" . note) ("number" . number) ("organization" . organization) ("pages" . pages) ("publisher" . publisher) ("school" . school) ("series" . series) ("title" . title) ("type" . type) ("volume" . volume) ("year" . year) ;; The following fields are non-standard. ;; Add your own here. ("abstract" . abstract) ("errata" . errata) ("isbn" . isbn) ("issn" . issn) ("keywords" . keywords) ("language" . language) ("lcnum" . lcnum) ("updated" . updated) ("warnings" . warnings)) "This constant contains a list of valid BibTeX field names, some of which will be ignored by the standard BibTeX styles.") ;;}}} ;;{{{ BibTeX-fields (defconst BibTeX-fields (eval-when-compile (mapcar 'cdr BibTeX-field-alist)) "A list of all acceptable fieldnames.") (defconst BibTeX-special-fields '(BibTeX-entry-type BibTeX-tag BibTeX-val BibTeX-var) "A list of fields that have no print name.") ;;}}} ;;{{{ BibTeX-string-alist (defvar BibTeX-string-alist '(("jan" . "January") ("feb" . "February") ("mar" . "March") ("apr" . "April") ("may" . "May") ("jun" . "June") ("jul" . "July") ("aug" . "August") ("sep" . "September") ("oct" . "October") ("nov" . "November") ("dec" . "December")) "This variable contains the string abbreviations and their expansions.") ;;}}} ;;{{{ BibTeX-alternate-formats (defconst BibTeX-alternate-formats (eval-when-compile (cons '("generic" . "bibtex.fmt") (mapcar (lambda (x) (cons (nth 0 x) (nth 1 x))) BibTeX-entry-type-alist))) "A list of formats for different BibTeX entry types.") ;;}}} ;;{{{ Keymaps (define-key database-view-mode-map "\C-c\C-v" 'BibTeX-validate-displayed-record) (define-key database-view-mode-map "\C-c\C-f" 'BibTeX-set-format) ;;}}} ;;{{{ User Options (defvar BibTeX-multiple-format t "*Turns entry type dependent format selection on.") (defvar BibTeX-use-default-format t "*Turns the use of the default format for new database entries on.") ;;}}} ;;{{{ Miscellaneous (defvar BibTeX-default-format '("generic" . "bibtex.fmt") "contains the format info of the last record on display") ;;}}} ;;}}} ;;{{{ Predicates and Other Inline Functions ;; We need to check for nil although the default type used by ;; `database-set-fieldnames-to-list' is `string', since `db-make-record' ;; does not use this information. I contemplated changing the ;; definition of `db-make-record', but this might cause problems for ;; other databases. ;; Return t if FIELD is nil or "". (defsubst BibTeX-field-empty-p (field) (or (null field) (string-equal field ""))) ;; Return t if FIELD is neither nil nor "". (defsubst BibTeX-field-not-empty-p (field) (and field (not (string-equal field "")))) ;; Return a record for DATABASE. Default field value is "". (defsubst BibTeX-make-record (database) (make-vector (length (database-fieldnames database)) "")) ;;}}} ;;{{{ Accessor Functions ;; Looks up an ABBREVIATION in BibTeX-string-alist. Returns the ;; expansion, if there is one. (defsubst BibTeX-get-expansion (string) (cdr (assoc (downcase string) BibTeX-string-alist))) ;; Returns the print name of FIELD. (defsubst BibTeX-get-print-name (symbol) (car (rassq symbol BibTeX-field-alist))) ;; Returns the field name of STRING. (defsubst BibTeX-get-field-name (string) (cdr (assoc (downcase string) BibTeX-field-alist))) ;; Looks up TYPE in BibTeX-entry-type-alist. Returns a list of ;; required BibTeX fields. (defsubst BibTeX-get-required-field-list (entry-type) (nth 2 (assoc (downcase entry-type) BibTeX-entry-type-alist))) ;;}}} ;;{{{ Delimiting Records ;; This could have been done with regular expressions, of course, but ;; this way it seemed safer, since the BibTeX files I looked at all ;; tended to have all kinds of stuff between the entries. ;; Unfortunately, folding information and comments will be lost ;; converting the database into EDB internal representation. ;; Therefore, comments should be placed within the record itself, say ;; in a field with the name "COMMENT", which will simply be ignored by ;; BibTeX. (defun BibTeX-delimit-record (prev-end-pos) "This is the sepinfo-sep-function, which takes the end position of the previous record as an argument and returns a dotted list of the end position of this record and the starting position of the next record." (if (re-search-forward "^[ \t]*@\\([A-z]*\\)[ \t\n]*\\([({]\\)" nil t 2) (cons (match-beginning 0) (match-beginning 0)) (list (point-max)))) ;;}}} ;;{{{ Delimiting Fields ;;{{{ BibTeX-find-value (defun BibTeX-find-value () "Returns the value of a BibTeX field, can handle concatenations." (let ((result "")) (catch 'done (while (skip-chars-forward " \t\n") ;; Skip over whitespace. (let ((start (point)) (char (char-after (point)))) (cond ((or (char-equal char ?\,) ; end of field (char-equal char ?\}) ; end of record (char-equal char ?\))) ; end of record ;; Hit the end of field (and record maybe). (throw 'done result)) ((char-equal char ?#) ; concatenation operator ;; Ignore: abbreviations are handled later (forward-char 1)) ((or (char-equal char ?\") ; beginning of delimited token (char-equal char ?{)) ; beginning of delimited token ;; Move to the end of the delimited token and add the ;; token to result. (forward-sexp) ; this requires a suitable syntax table (setq result (concat result (buffer-substring (+ start 1) (- (point) 1))))) ((looking-at "\\([0-9]+\\)\\b") ; number ;; Add token matched to result. (setq result (concat result (match-string 1))) (goto-char (match-end 1))) (t ; abbreviation ;; Move to the end of token, mark it and add it to ;; result. (forward-word 1) (setq result (concat result "#" (buffer-substring start (point)) "#"))))))))) ;;}}} ;;}}} ;;{{{ Reading the Database ;;{{{ BibTeX-set-up-db-buffer ;; This function should be added to db-before-read-hooks for the ;; database reading functions to work correctly! (defun BibTeX-set-up-db-buffer () "Sets the syntax table of db-buffer to the BibTeX syntax table." (save-excursion (set-buffer db-buffer) (set-syntax-table bibtex-mode-syntax-table)) ;; Clean up. (remove-hook 'db-after-read-hook 'BibTeX-set-up-db-buffer)) ;;}}} ;;{{{ BibTeX-rrfr ;; This function assumes the buffer is narrowed to the region. (defun BibTeX-rrfr () "Reads a BibTeX record from the region and returns a database record with the appropriate slots set." (if (re-search-forward "@\\([A-z]+\\)[ \t\n]*[({]" nil t) (let ((record (BibTeX-make-record database)) (warnings "") (entry-type (downcase (match-string 1)))) (cond ((string-equal entry-type "string") (db-record-set-field record 'BibTeX-entry-type "string") ;; This special entry types contains only two items ;; of interest, namely an abbreviation and its ;; expansion. First, we look for the abbreviation: (re-search-forward "\\([^ \"#%'(),={}\n\t]+\\)[ \t]*=[ \t]*" nil t) (db-record-set-field record 'BibTeX-var (downcase (match-string 1))) ;; Anything that follows should be the expansion. (db-record-set-field record 'BibTeX-val (BibTeX-find-value))) ((string-equal entry-type "preamble") (db-record-set-field record 'BibTeX-entry-type "preamble") ;; This special entry-type contains only one field. (db-record-set-field record 'BibTeX-val (BibTeX-find-value))) ((assoc entry-type BibTeX-entry-type-alist) (db-record-set-field record 'BibTeX-entry-type entry-type) ;; Note: the following regexp deliberately accepts ;; empty tags, as long as the comma is present. (re-search-forward "[ \t\n]*\\(\\w*\\)[ \t\n]*," nil t) (db-record-set-field record 'BibTeX-tag (match-string 1)) (while (re-search-forward "\\(\\w+\\)[ \t\n]*=" nil t) (let ((current-field (BibTeX-get-field-name (downcase (match-string 1))))) (if current-field (db-record-set-field record current-field (BibTeX-find-value)) (setq warnings (concat warnings (format "\nUnknown field %s ignored." (match-string 1)))) (message "Warning: ignoring unknown field: %s." (match-string 1))))) (if (not (string-equal warnings "")) (db-record-set-field record 'warnings (substring warnings 1))))) record) ;; In case something went wrong, return an empty record. Returning ;; anything else might cause severe problems. (BibTeX-make-record database))) ;;}}} ;;{{{ BibTeX-define-abbreviations ;; As with BibTeX itself, strings must be defined before they are ;; used. Edbibtex will simply issue a warning if an undefined string ;; is used. (defun BibTeX-define-abbreviations () "db-after-read-hook for defining abbreviations." (db-maprecords (lambda (record) (let ((abbreviation (db-record-field record 'BibTeX-var))) ;; This is a string entry, update the list of ;; abbreviations. (if (not (or (BibTeX-field-empty-p abbreviation) (BibTeX-get-expansion abbreviation))) (setq BibTeX-string-alist (cons (cons (downcase abbreviation) (db-record-field record 'BibTeX-val)) BibTeX-string-alist))))))) ;;}}} ;;}}} ;;{{{ Writing the Database (defun BibTeX-wrfr (record) "Write RECORD to buffer." (let ((entry-type (downcase (db-record-field record 'BibTeX-entry-type)))) (cond ((string-equal entry-type "string") (insert (format "@string{ %s = {%s} }\n" (db-record-field record 'BibTeX-var) (db-record-field record 'BibTeX-val)))) ((string-equal entry-type "preamble") (insert (format "@preamble{ {%s} }\n" (db-record-field record 'BibTeX-val)))) (t (insert (format "@%-16s%s" (concat (downcase (db-record-field record 'BibTeX-entry-type)) "{ " (db-record-field record 'BibTeX-tag)))) (save-excursion (insert (mapconcat (lambda (field) (let ((value (db-record-field record field))) (if (BibTeX-field-empty-p value) "" (format ",\n %-15s{%s}" (concat (BibTeX-get-print-name field) " = ") value)))) BibTeX-fields "") "\n}\n")) (while (re-search-forward "\\({?\\)#\\([^ \"#%'(),={}\n\t]+\\)#\\(}?\\)" nil 1) (let ((replacement (match-string 2))) (if (not (string-equal (match-string 1) "{")) (setq replacement (concat "} # " replacement))) (if (not (string-equal (match-string 3) "}")) (setq replacement (concat replacement " # {"))) (replace-match replacement nil t))))))) ;;}}} ;;{{{ Displaying the Database ;;{{{ BibTeX-set-format (defun BibTeX-set-format () "This will prompt the user for an entry type and set the display format accordingly, if the entry type is undefined (this is the case with entries newly added)." (interactive) (let* ((completion-ignore-case t) (format (completing-read "Entry type: " BibTeX-alternate-formats nil t))) (dbf-set-this-record-modified-p t) (dbf-displayed-db-record-set-field-and-redisplay 'BibTeX-entry-type format) (db-change-format format))) ;;}}} ;;{{{ BibTeX-set-format-from-data (defun BibTeX-set-format-from-data (record) "This checks the entry type of the record on display and chooses an appropriate format from BibTeX-entry-type-alist." (if BibTeX-multiple-format (let ((entry-type (downcase (db-record-field record 'BibTeX-entry-type)))) (if (BibTeX-field-empty-p entry-type) (if BibTeX-use-default-format (let ((entry-type (car BibTeX-default-format))) (db-change-format entry-type) (db-record-set-field record 'BibTeX-entry-type entry-type)) (BibTeX-set-format)) (progn (db-change-format entry-type) (setq BibTeX-default-format (assoc entry-type BibTeX-alternate-formats))))))) ;;}}} ;;}}} ;;{{{ Validating Entries ;;{{{ BibTeX-check-abbreviations (defun BibTeX-check-abbreviations (record) (mapconcat (lambda (field) (let ((string (db-record-field record field)) (pos 0)) (if (BibTeX-field-not-empty-p string) (while (string-match "#\\([^#%\"'(),={}\t\n ]+\\)#" string pos) (setq pos (match-end 1)) (let ((match (match-string 1 string))) (if (BibTeX-get-expansion match) "" (format "\nUndefined abbreviation %s in field %s" match (BibTeX-get-print-name field)))) "")))) BibTeX-fields "")) ;;}}} ;;{{{ BibTeX-validate-displayed-record (defun BibTeX-validate-displayed-record (&optional record) "Validate the record currently on display." (interactive) (let* ((record (or record (dbf-displayed-record))) (warnings (concat (BibTeX-validate-record record) (BibTeX-check-abbreviations record)))) (dbf-set-this-record-modified-p t) (dbf-displayed-record-set-field-and-redisplay 'updated (current-time-string)) (dbf-displayed-record-set-field-and-redisplay 'warnings (if (string-equal warnings "") ; remove first newline if necessary warnings (substring warnings 1))))) ;;}}} ;;{{{ BibTeX-validate-record (defun BibTeX-validate-record (record) "Returns warnings if RECORD is not BibTeX conforming." (let ((entry-type (db-record-field record 'BibTeX-entry-type))) (cond ((string-equal entry-type "preamble")) ;; Do nothing about preambles. ((string-equal entry-type "string") ;; Check for extraneous hash symbols and update ;; BibTeX-string-alist if necessary. (let ((abbreviation (db-record-field record 'BibTeX-var))) (if (BibTeX-field-empty-p abbreviation) nil (if (string-match "#?\\([^#%\"'(),={}\t\n ]+\\)#?" abbreviation) (progn (db-record-set-field record 'BibTeX-var (match-string 1 abbreviation)) (dbf-set-this-record-modified-p t))) (if (not (BibTeX-get-expansion abbreviation)) (setq BibTeX-string-alist (cons (cons abbreviation (db-record-field record 'BibTeX-val)) BibTeX-string-alist)))))) (t ;; This should be a standard record. (let ((warnings (concat (if (BibTeX-field-empty-p (db-record-field record 'BibTeX-tag)) "\nThis record is not tagged." "") (mapconcat (lambda (field) (if (atom field) (if (BibTeX-field-empty-p (db-record-field record field)) (format "\nRequired field %s is empty." (BibTeX-get-print-name field)) "") ;; If it's not an atom, it has to be a list ;; with exactly three elements. (let ((first (nth 1 field)) (second (nth 2 field))) (if (eq (car field) 'xor) (cond ((and (BibTeX-field-empty-p (db-record-field record first)) (BibTeX-field-empty-p (db-record-field record second))) (format "\nField %s and field %s should not both be empty." first second)) ((and (BibTeX-field-not-empty-p (db-record-field record first)) (BibTeX-field-not-empty-p (db-record-field record second))) (format "\nField %s and field %s should not both be set." first second)) (t "")) (if (and (BibTeX-field-empty-p (db-record-field record first)) (BibTeX-field-empty-p (db-record-field record second))) (format "\nField %s and field %s should not both be empty." first second)))))) (BibTeX-get-required-field-list entry-type) "")))) warnings))))) ;;}}} ;;}}} (provide 'edbibtex) ;;{{{ Local Variables ;; Local Variables: ;; mode: emacs-lisp ;; folded-file: t ;; End: ;;}}} edb-1.31/examples/edbibtex/edbibtex.texinfo0000444000175000017500000003431610745370011017157 0ustar ttnttn\input texinfo @setfilename edbibtex.info @settitle edbibtex User's Manual @setchapternewpage odd @ifinfo This file documents @code{edbibtex}, a collection of functions for processing BibTeX files with EDB, Michael Ernst's Emacs Database. Copyright (C) 1995 Michael Burschik Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Foundation. @end ifinfo @titlepage @title edbibtex @subtitle A BibTeX Package for EDB @subtitle Version 0.4 @subtitle March 1995 @author Michael Burschik @page @vskip 0pt plus 1filll Copyright @copyright{} 1995 Michael Burschik Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Foundation. @end titlepage @node Top, , , (dir) @code{edbibtex.el} is a collection of functions which should prove useful for maintaining BibTeX database files using EDB, Michael Ernst's marvelous Emacs Database. @code{edbibtex.el} contains functions for reading, writing, formatting and validating such files. You should also have @file{BibTeX.dba}, an EDB auxiliary file for use with BibTeX style bibliography files, and a set of sample formats. I am indebted to Michael Ernst and Thorsten Ohl for the inspiration their code provided and the information they supplied. I would also like to thank Alastair Burt , James Crotinger and Martin Maechler for bug reports. Please send all bug reports, suggestions for improvement, threats and praise (if any) to: Michael Burschik . @menu * Copying:: How you can copy and share @code{edbibtex}. * Caveats:: Where @code{edbibtex} will fail you. * Features:: What @code{edbibtex} should do for you. * Installation:: How to install @code{edbibtex}. * Customization:: How to pinch and twiddle @code{edbibtex}. * Concept Index:: Index of concepts. @end menu @node Copying, Caveats, Top, Top @chapter Copying @cindex Copying 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @node Caveats, Features, Copying, Top @chapter Caveats @cindex Caveats @cindex What doesn't work @menu * Comments:: The fate of comments, folding information, etc. * Strings:: @code{@@string} commands and string concatenation. @end menu @node Comments, Strings,, Caveats @section Comments @cindex Comments Many BibTeX files tend to have comments, fancy delimiting lines or folding information between the entries. I think the database reading functions will skip over this stuff unharmed, but they will discard all such additional information. In other words: @example Anything which is not recognized as a BibTeX entry will be discarded. @end example My official position on comments is that they should be put in some ignored BibTeX field, such as @samp{ABSTRACT} or @samp{MY-COMMENT}. I might write functions to look for comments in other places, but don't count on it. @node Strings,, Comments, Caveats @section Strings BibTeX's @code{@@string} command is supported. Abbreviations will be displayed enclosed by @samp{#} characters, which should be safe for enough for @TeX{} as long as the catcodes have not been changed. The abbreviations will not, however, be written to the database file that way. If abbreviations are entered in database-edit-mode, they must also be enclosed this way, so that @code{edbibtex} will be able to recognize them (@pxref{Defining Abbreviations}, for details and examples). @refill @node Features, Installation, Caveats, Top @chapter Features @cindex Features @menu * Defining Abbreviations:: BibTeX's @@string command. * String Concatenation:: BibTeX's @samp{#} operator. * Preambles:: BibTeX's @@preamble command. * Validation:: Validating the database entries. @end menu @node Defining Abbreviations, String Concatenation,, Features @section Defining Abbreviations @cindex Defining Abbreviations @findex BibTeX's @code{@@string} command @code{edbibtex} is able to handle BibTeX's @code{@@string} command. String declarations are considered to be a valid entry type and are associated with a separate format file. @refill Abbreviations will be displayed enclosed by @samp{#} characters, which should be safe for enough for @TeX{} as long as the catcodes have not been changed. The abbreviations will not, however, be written to the database file that way. If abbreviations are entered in database-edit-mode, they must also be enclosed this way. @refill Thus, if your BibTeX database file contains the command @example @@string( AMS = "American Mathematical Society" ) @end example you might use this abbreviation somewhere in your database. Your display buffer should then look something like this: @example author: E.G. Anybody title: Some Remarks on Things publisher: #AMS# @end example Make sure you always tag your abbreviations in this way. @node String Concatenation, Preambles, Defining Abbreviations, Features @section String Concatenation @cindex String Concatenation @findex BibTeX's concatenation operator @findex @samp{#} @code{edbibtex} supports BibTeX's string concatenation feature. This means that you can write things like this: @example @@string( AMS = "American Mathematical Society" ) @@book@{Ore, author = "Oystein Ore", title = "Theory of Graphs", series = AMS # " Colloquium Publications" ... @} @end example In your data display buffer, @code{edbibtex} will display this as: @example series: #AMS# Colloquium Publications @end example You can use any amount of concatenation. @node Preambles, Validation, String Concatenation, Features @section Preambles @cindex Preambles @findex BibTeX's @code{@@preamble} command BibTeX's @@preamble feature, which allows you to define new macros for your bibliography, is also supported by @code{edbibtex}. @@preamble entries have their own display format. @node Validation,, Preambles, Features @section Validation @cindex Validation @findex BibTeX-validate-entry All entries are checked both for undefined abbreviations and for violations of the BibTeX entry type requirements. This is done automatically when the database file is read and whenever a record is modified. It can also be done interactively with the function @code{BibTeX-validate-entry}, which is bound to @kbd{C-c C-v} by default. If you validate a string record, then @code{BibTeX-string-alist} is updated. Your new abbreviation is now defined and will no longer cause warnings. @node Installation, Customization, Features, Top @chapter Installation @cindex Installation @code{edbibtex} consists of the following files: @enumerate @item The main code file: @file{edbibtex.el} @item A byte compile script: @file{compile.el} @item An EDB auxiliary file: @file{bibtex.dba} @item Format files: @file{article.fmt}, @file{bibtex.fmt}, @file{book.fmt}, @file{booklet.fmt}, @file{inbook.fmt}, @file{incollection.fmt}, @file{inproceedings.fmt}, @file{manual.fmt}, @file{mastersthesis.fmt}, @file{misc.fmt}, @file{phdthesis.fmt}, @file{preamble.fmt}, @file{proceedings.fmt}, @file{string.fmt}, @file{techreport.fmt}, @file{unpublished.fmt} @refill @item Documentation: @file{edbibtex.texinfo} @item A makefile: @file{Makefile} @end enumerate Edit @file{Makefile}, then type @kbd{make all} and @kbd{make install}. If you haven't got make, byte-compile @file{edbibtex.el} and put it somewhere in your load path. You can do this by either loading @file{compile.el} or by loading @file{edbibtex.el} before byte-compiling @file{edbibtex.el}. Make a copy of @file{bibtex.dba}, change its name to fit the name of your BibTeX database and put it somewhere it will be found by EDB. If, for example, your database is called @file{PhD-Thesis.bibliography}, then rename the copy of @file{BibTeX.dba} to @file{PhD-Thesis.dba}. @refill @vindex db-format-file-path Put the format files somewhere in EDB's @code{db-format-file-path}. It is also a good idea to have a format file with the same base name as your database, so that you will not be prompted for a format every time you load it. This file should be a generic format file like @file{bibtex.fmt}. Copy this format file and call it @file{PhD-Thesis.fmt} or whatever. @refill Reading and writing BibTeX database files is complicated and time-consuming. If you are thinking of maintaining database files containing more than two or three hundred records, you should think about keeping two versions: workday versions for use with EDB (in EDB's internal layout) and Sunday versions for BibTeX to work with (in BibTeX's file layout). You can control the on-disk representation of your database files with @code{db-toggle-internal-file-layout}. @node Customization, Concept Index, Installation, Top @chapter Customization @cindex Customization The file @file{BibTeX.dba} is used to set a number of per-database variables that modify the behaviour of @code{EDB} and @code{edbibtex}. Before you do anything else, make sure that you have a copy of @file{bibtex.dba} hidden away in some safe place. Make a copy of the file and rename it so that it will fit your database file (e.g., @file{PhD-Thesis.dba}) and customize that copy only. A number of constants and variables that should be database independent are defined in @code{edbibtex.el} itself. @menu * Entry Types:: Valid BibTeX entry types. * Fields:: Valid BibTeX field names. * Abbreviations:: Pre-defined abbreviations. * Multiple Formats:: Using entry type dependent formats. @end menu @node Entry Types, Fields,, Customization @section Entry Types @cindex Entry Types @vindex BibTeX-entry-type-alist @code{BibTeX-entry-type-alist} is an association list containing all valid BibTeX entry types and the format files associated with them. You shouldn't want to change the entry types, but you might want to give other names to your format files. Note that the list of valid entry types includes @code{@@string} and @code{@@preamble} entries. @code{BibTeX-entry-type-alist} is defined in @code{edbibtex.el}. @node Fields, Abbreviations, Entry Types, Customization @section Fields @cindex Fields @vindex BibTeX-field-alist @code{BibTeX-field-alist} is an association list containing all standard BibTeX entry fields (BibTeX version 0.99a) and a few additional fields that happened to pop up in my own BibTeX database files or Thorsten Ohl's example file. You might want to add a few of your own, depending on what information you require and what style you are using. @code{BibTeX-field-alist} is defined in @code{edbibtex.el}. @node Abbreviations, Multiple Formats, Fields, Customization @section Abbreviations @cindex Abbreviations @vindex BibTeX-string-alist @code{BibTeX-string-alist} is an association list containing a few standard abbreviations and their expansions. You can add whatever you like, or set it to @code{nil}. This association list will be updated whenever a string entry is read from the database file or a newly added string entry is validated (@pxref{Validation}, for details). @code{BibTeX-string-alist} is defined in @code{edbibtex.el}. @node Multiple Formats,, Abbreviations, Customization @section Multiple Formats @cindex Multiple Formats @findex db-change-format @findex BibTeX-set-format @vindex BibTeX-multiple-format @vindex BibTeX-use-default-format If the per-database variable @code{BibTeX-multiple-format} is set to @code{nil}, then only a generic format will be used to display records. If @code{BibTeX-multiple-format} was set from the auxiliary file, then this format will be the one defined as @code{GENERIC}; otherwise it will be the format of the record on display when the variable was set. In any case, however, you can change the format with @code{db-change-format}. @refill If @code{BibTeX-multiple-format} is set to anything other than @code{nil}, @code{db-change-format} will have no effect at all; the format of an entry will depend on the format file associated with its entry type. If @code{BibTeX-use-default-format} is set to something other than @code{nil}, then the format of a newly added entry (i.e., an entry without a valid entry type) will be the default format (i.e., the format of the entry currently on display). You can change this format with @code{BibTeX-set-format}. If @code{BibTeX-use-default-format} is set to @code{nil}, you will be prompted for an appropriate format. @refill @page @node Concept Index,, Customization, Top @unnumbered Concept Index @printindex cp @contents @bye edb-1.31/examples/edbibtex/inbook.fmt0000444000175000017500000000217310745370011015760 0ustar ttnttn******************************** INBOOK ******************************** Code: \BibTeX-tag ................................................................Required Author: \author Editor: \editor Title: \title Chapter: \chapter Pages: \pages Publisher: \publisher Year: \year ................................................................Optional Volume: \volume Series: \series Address: \address Edition: \edition Month: \month Note: \note .................................................................Ignored Journal: \journal Number: \number Booktitle: \booktitle School: \school Institution: \institution Organization: \organization Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ******************************** INBOOK ******************************** edb-1.31/examples/edbibtex/incollection.fmt0000444000175000017500000000217310745370011017161 0ustar ttnttn***************************** INCOLLECTION ***************************** Code: \BibTeX-tag ................................................................Required Author: \author Title: \title Booktitle: \booktitle Publisher: \publisher Year: \year ................................................................Optional Editor: \editor Chapter: \chapter Pages: \pages Address: \address Month: \month Note: \note .................................................................Ignored Journal: \journal Series: \series Volume: \volume Number: \number Edition: \edition School: \school Institution: \institution Organization: \organization Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ***************************** INCOLLECTION ***************************** edb-1.31/examples/edbibtex/inproceedings.fmt0000444000175000017500000000217310745370011017330 0ustar ttnttn**************************** INPROCEEDINGS ***************************** Code: \BibTeX-tag ................................................................Required Author: \author Title: \title Booktitle: \booktitle Year: \year ................................................................Optional Editor: \editor Pages: \pages Organization: \organization Publisher: \publisher Address: \address Month: \month Note: \note .................................................................Ignored Journal: \journal Series: \series Volume: \volume Number: \number Chapter: \chapter Edition: \edition School: \school Institution: \institution Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings **************************** INPROCEEDINGS ***************************** edb-1.31/examples/edbibtex/manual.fmt0000444000175000017500000000217310745370011015754 0ustar ttnttn******************************** MANUAL ******************************** Code: \BibTeX-tag ................................................................Required Title: \title ................................................................Optional Author: \author Organization: \organization Address: \address Edition: \edition Month: \month Year: \year Note: \note .................................................................Ignored Editor: \editor Journal: \journal Series: \series Volume: \volume Number: \number Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle School: \school Institution: \institution Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ******************************** MANUAL ******************************** edb-1.31/examples/edbibtex/mastersthesis.fmt0000444000175000017500000000217310745370011017375 0ustar ttnttn**************************** MASTERSTHESIS ***************************** Code: \BibTeX-tag ................................................................Required Author: \author Title: \title School: \school Year: \year ................................................................Optional Address: \address Month: \month Note: \note .................................................................Ignored Editor: \editor Journal: \journal Series: \series Volume: \volume Number: \number Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition Institution: \institution Organization: \organization Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings **************************** MASTERSTHESIS ***************************** edb-1.31/examples/edbibtex/misc.fmt0000444000175000017500000000217310745370011015432 0ustar ttnttn********************************* MISC ********************************* Code: \BibTeX-tag ................................................................Required ................................................................Optional Author: \author Title: \title Howpublished: \howpublished Month: \month Year: \year Note: \note .................................................................Ignored Editor: \editor Journal: \journal Series: \series Volume: \volume Number: \number Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition School: \school Institution: \institution Organization: \organization Address: \address Type: \type Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ********************************* MISC ********************************* edb-1.31/examples/edbibtex/phdthesis.fmt0000444000175000017500000000217310745370011016472 0ustar ttnttn****************************** PHDTHESIS ******************************* Code: \BibTeX-tag ................................................................Required Author: \author Title: \title School: \school Year: \year ................................................................Optional Address: \address Month: \month Note: \note .................................................................Ignored Editor: \editor Journal: \journal Series: \series Volume: \volume Number: \number Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition Institution: \institution Organization: \organization Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ****************************** PHDTHESIS ******************************* edb-1.31/examples/edbibtex/preamble.fmt0000444000175000017500000000037110745370011016264 0ustar ttnttn******************************* PREAMBLE ******************************* ................................................................Required Preamble: \BibTeX-val ******************************* PREAMBLE ******************************* edb-1.31/examples/edbibtex/proceedings.fmt0000444000175000017500000000217310745370011017001 0ustar ttnttn***************************** PROCEEDINGS ****************************** Code: \BibTeX-tag ................................................................Required Title: \title Year: \year ................................................................Optional Editor: \editor Publisher: \publisher Organization: \organization Address: \address Month: \month Note: \note .................................................................Ignored Author: \author Journal: \journal Series: \series Volume: \volume Number: \number Pages: \pages Chapter: \chapter Booktitle: \booktitle Edition: \edition School: \school Institution: \institution Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ***************************** PROCEEDINGS ****************************** edb-1.31/examples/edbibtex/string.fmt0000444000175000017500000000042410745370011016002 0ustar ttnttn******************************* STRING ********************************* ................................................................Required Abbreviation: \BibTeX-var Expansion: \BibTeX-val ******************************* STRING ********************************* edb-1.31/examples/edbibtex/techreport.fmt0000444000175000017500000000217310745370011016656 0ustar ttnttn****************************** TECHREPORT ****************************** Code: \BibTeX-tag ................................................................Required Author: \author Title: \title Institution: \institution Year: \year ................................................................Optional Type: \type Number: \number Address: \address Month: \month Note: \note .................................................................Ignored Editor: \editor Journal: \journal Series: \series Volume: \volume Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition School: \school Organization: \organization Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ****************************** TECHREPORT ****************************** edb-1.31/examples/edbibtex/unpublished.fmt0000444000175000017500000000217310745370011017021 0ustar ttnttn***************************** UNPUBLISHED ****************************** Code: \BibTeX-tag ................................................................Required Author: \author Title: \title Note: \note ................................................................Optional Month: \month Year: \year .................................................................Ignored Editor: \editor Journal: \journal Series: \series Volume: \volume Number: \number Pages: \pages Chapter: \chapter Publisher: \publisher Booktitle: \booktitle Edition: \edition School: \school Institution: \institution Organization: \organization Address: \address Type: \type Howpublished: \howpublished Key: \key Crossref: \crossref ISBN: \isbn ISSN: \issn LCNumber: \lcnum Errata: \errata Keywords: \keywords Language: \language Remarks: \annote Updated: \updated Warnings: \warnings ***************************** UNPUBLISHED ****************************** edb-1.31/examples/eicsw.dat0000644000175000017500000000207710745370011014012 0ustar ttnttnNM: amd SD: Automounting daemon VR: 5.2.2.2 MA: rs6000 OS: AIX3.2 ID: 07/15/92 IR: aks@anywhere IN: Must execute "amd" with MALLOCTYPE=3.1 set BP: /eci/amd/bin BL: amd, amq MP: /eci/amd/man SR: /fs/src6/local/sys/amd5.3beta UD: 07/15/92 NM: archie SD: FTP index archive database server query client program VR: 1.3 MA: rs6000 OS: AIX3.2 ID: 01/27/92 IR: aks@anywhere BP: /eci/bin BL: archie MP: /eci/man SR: /fs/src6/local/data/archie UD: 01/27/92 NM: areacode SD: Convert areacodes to cities and states MA: rs6000 OS: AIX3.2 ID: 06/09/92 IR: aks@anywhere BP: /eci/bin BL: areacode SR: ~aks/src/Data/areacode UD: 06/09/92 NM: emacs SD: GNU's programmable, full-screen editor with X support VR: 18.56 MA: rs6000 OS: AIX3.2 ID: 08/07/92 IR: aks@anywhere IN: FLOAT_PATCH installed, supporting true floating point type. GMALLOC_PATCH installed, allowing Emacs to use GNU malloc package. BP: /eci/bin BL: emacs, ctags, etags, emacsclient, emacs-18.58, ctags-18.58, etags-18.58, emacsclient-18.58 LP: /eci/emacs MP: /eci/man IP: /eci/emacs/info/emacs SR: /fs/src1/Gnu/emacs UD: 08/07/92 edb-1.31/examples/eicsw.dba0000444000175000017500000000677510745370011013777 0ustar ttnttn;;; eicsw.dba --- Define the ECI Software database ;; Define some enumerated types ;; "arch" (edb-define-enumtype 'arch '("rs6000" ;IBM "NeXT" ;NeXT "sun3" "sun4" ;Sun "mipsel" ;DECstation 5000 "r3000" ;SGI R3000 "r4000" ;SGI R4000 "mac" ;Macintosh "any" ;any ) nil) ;; "os" (edb-define-enumtype 'os '("AIX3.2" "NeXTOS2.0" "NeXTOS3.0" "SunOS4.0.3" "SunOS4.1.1" "SunOS4.1.2" "Solaris2.0" "Solaris2.1" "Ultrix4.1" "Ultrix4.2" "IRIX4.1" "IRIX4.2" "MacOS6.0.5" "MacOS7.0" "any" ;any ) nil) ;; "short-string": both a one-line-string and a string-or-nil. (edb-define-displaytype 'short-string 'one-line-string :actual->display 'db-string-or-nil->string) (edb-define-recordfieldtype 'short-string 'one-line-string :type 'short-string :order-fn 'db-string-or-nil-order-ci :sort-fn 'db-string-or-nil-lessp-ci :match-function 'db-string-or-nil-match-function) (require 'edb-t-timedate1) (edb-define-recordfieldtype 'suredate 'date ;; writing: YYYY-MM-DD :actual->stored 'edb-t-timedate1:format-date-iso ;; reading: either YYYY-MM-DD or MM/DD/YY :stored->actual 'edb-t-timedate1:parse-date-string) ;; Now define the database fields and overriding attributes (db-tagged-setup ;; fields '(((name . short-string) "NM" "Name of software") ((desc . string-or-nil) "SD" "Software description") ((version . short-string) "VR" "Version of software installed") ((arch . arch) "MA" "Machine architecture of installation") ((os . os) "OS" "Operating System") ((restric . string-or-nil) "OR" "Operational restrictions (if any)") ((installdate . suredate) "ID" "Date installed") ((installer . short-string) "IR" "Who installed it") ((installnotes . string-or-nil) "IN" "Installation Notes") ((binpath . short-string) "BP" "Path to binaries") ((binlist . string-or-nil) "BL" "List of binaries (possibly linked)") ((libpath . short-string) "LP" "Path to libraries") ((liblist . string-or-nil) "LL" "List of libraries (eg: \"-lX11\")") ((manpath . short-string) "MP" "Path to \"man\" pages") ((infopath . short-string) "IP" "Path to GNU info file") ((helppath . short-string) "HP" "Path to file or command to help user with software") ((source . short-string) "SR" "Source location: FTP site, or local filesystem") ((updatedate . suredate) "UD" "Last update date") ((updater . short-string) "UR" "Who did the last update") ((updatenotes . string-or-nil) "UN" "Notes on last update")) ;; overriding attributes :pre-tag-regexp "" :tag-chars "A-Z" :separator-regexp ":[ \t]*" :separator-output ":\t" :continuation-regexp "^[ \t]+" :continuation-output "\t") (setf (database-print-name database) "ECI Software Database") (dbf-set-summary-format "\\name,width=12 \\version,width=6 \\updatedate,date-mmddyy,width=8 \\arch,width=10 \\os,width=10") (defun swdb-record-defaults (new-rec database) "Provide defaults for new records in the database." (let ((curdate (edb-t-timedate1:parse-date-string (current-time-string))) (curuser (concat (user-login-name) "@" (system-name)))) (db-record-set-field new-rec 'installdate curdate database) (db-record-set-field new-rec 'installer curuser database) (db-record-set-field new-rec 'updatedate curdate database))) (setq db-new-record-function 'swdb-record-defaults) ;;; eicsw.dba ends here edb-1.31/examples/eicsw.edb0000444000175000017500000001164410745370011013772 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;; Define some enumerated types ;; "arch" (edb-define-enumtype 'arch '("rs6000" ;IBM "NeXT" ;NeXT "sun3" "sun4" ;Sun "mipsel" ;DECstation 5000 "r3000" ;SGI R3000 "r4000" ;SGI R4000 "mac" ;Macintosh "any" ;any ) nil) ;; "os" (edb-define-enumtype 'os '("AIX3.2" "NeXTOS2.0" "NeXTOS3.0" "SunOS4.0.3" "SunOS4.1.1" "SunOS4.1.2" "Solaris2.0" "Solaris2.1" "Ultrix4.1" "Ultrix4.2" "IRIX4.1" "IRIX4.2" "MacOS6.0.5" "MacOS7.0" "any" ;any ) nil) ;; "short-string": both a one-line-string and a string-or-nil. (edb-define-displaytype 'short-string 'one-line-string :actual->display 'db-string-or-nil->string) (edb-define-recordfieldtype 'short-string 'one-line-string :type 'short-string :order-fn 'db-string-or-nil-order-ci :sort-fn 'db-string-or-nil-lessp-ci :match-function 'db-string-or-nil-match-function) (require 'edb-t-timedate1) (edb-define-recordfieldtype 'suredate 'date ;; writing: always YYYY-MM-DD :actual->stored 'edb-t-timedate1:format-date-iso ;; reading: either YYYY-MM-DD or MM/DD/YY :stored->actual 'edb-t-timedate1:parse-date-string) ;; Now define the database fields and overriding attributes :tagged-setup '(:fields (((name . short-string) "NM" "Name of software") ((desc . string-or-nil) "SD" "Software description") ((version . short-string) "VR" "Version of software installed") ((arch . arch) "MA" "Machine architecture of installation") ((os . os) "OS" "Operating System") ((restric . string-or-nil) "OR" "Operational restrictions (if any)") ((installdate . suredate) "ID" "Date installed") ((installer . short-string) "IR" "Who installed it") ((installnotes . string-or-nil) "IN" "Installation Notes") ((binpath . short-string) "BP" "Path to binaries") ((binlist . string-or-nil) "BL" "List of binaries (possibly linked)") ((libpath . short-string) "LP" "Path to libraries") ((liblist . string-or-nil) "LL" "List of libraries (eg: \"-lX11\")") ((manpath . short-string) "MP" "Path to \"man\" pages") ((infopath . short-string) "IP" "Path to GNU info file") ((helppath . short-string) "HP" "Path to file or command to help user with software") ((source . short-string) "SR" "Source location: FTP site, or local filesystem") ((updatedate . suredate) "UD" "Last update date") ((updater . short-string) "UR" "Who did the last update") ((updatenotes . string-or-nil) "UN" "Notes on last update")) ;; overriding attributes :pre-tag-regexp "" :tag-chars "A-Z" :separator-regexp ":[ \t]*" :separator-output ":\t" :continuation-regexp "^[ \t]+" :continuation-output "\t") :name "ECI Software Database" :summary-format (mapconcat (lambda (pair) (format "\\%s,width=%d" (car pair) (cdr pair))) '((name . 12) (version . 6) ("updatedate,date-mmddyy" . 8) (arch . 10) (os . 10)) " ") :record-defaults (lambda () "Provide defaults for new records in the database." (let ((curdate (edb-t-timedate1:parse-date-string (current-time-string))) (curuser (concat (user-login-name) "@" (system-name)))) (list 'installdate curdate ; plist 'installer curuser 'updatedate curdate))) :display t ECI Software Database Name: \name Description: \desc,indent Version: \version Arch: \arch OS: \os Restrictions: \restric,indent Bin Path: \binpath Binary List: \binlist,indent Library Path: \libpath Library List: \liblist,indent Man Path: \manpath Info Path: \infopath Help Path: \helppath Source: \source Installed: \installdate,date-iso Installed By: \installer Install notes: \installnotes,indent Last Update: \updatedate,date-iso Updated By: \updater Update Notes: \updatenotes,indent :EOTB ;;; eicsw.edb ends here edb-1.31/examples/eicsw.fmt0000444000175000017500000000110310745370011014013 0ustar ttnttn ECI Software Database Name: \name Description: \desc,indent Version: \version Arch: \arch OS: \os Restrictions: \restric,indent Bin Path: \binpath Binary List: \binlist,indent Library Path: \libpath Library List: \liblist,indent Man Path: \manpath Info Path: \infopath Help Path: \helppath Source: \source Installed: \installdate,date-iso Installed By: \installer Install notes: \installnotes,indent Last Update: \updatedate,date-iso Updated By: \updater Update Notes: \updatenotes,indent edb-1.31/examples/forms-demo2-inherent.edb0000644000175000017500000000516610745370011016630 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "Public Domain Software Archive" :fields [arch-newsgroup arch-volume arch-issue (arch-article . integer) arch-shortname (arch-parts . integer) arch-from arch-longname arch-keywords arch-date arch-remarks] :field-order [arch-shortname] :summary-format "\\arch-shortname - \\arch-longname\n [\\arch-parts parts]" :substitutions [("\n" . "\C-k")] :display t ====== Public Domain Software Archive ====== \arch-shortname - \arch-longname Article: \arch-newsgroup/\arch-article Issue: \arch-issue Date: \arch-date Submitted by: \arch-from Keywords: \arch-keywords Parts: \arch-parts ====== Remarks ====== \arch-remarks :EOTB :report t Short name: \arch-shortname Long name: \arch-longname Article \arch-article in issue \arch-issue of \arch-newsgroup, appeared \arch-date :EOTB ;;; NOTE: Support for inherent data (specifying the `:data' control property) ;;; is EXPERIMENTAL. EDB 1.26 can read, but not write, this information. ;;; EDB 1.27 can both read and write this information. :data (:coding t :seqr read-line :seqw write-line) ["comp.sources.unix" "" "v11i008" 269 "getty-enable" 1 "tron@sc.nsc.com (Ronald S. Karr)" "Getty on/off programs for 4.[23] BSD" "" "890505" "This program can be used to dynamically enable / disable terminal\nlines on a BSD system.\n"] ["comp.sources.unix" "11" "v11i022" 283 "syslog" 1 "emory!arnold (Arnold D. Robbins {EUCC})" "Development version of syslog(3), for ATT, too" "" "28/08/1987" ""] ["comp.sources.unix" "11" "v11i033" 290 "less3" 3 "sun!intsc!convgt!mark" "The 'less' pager" "" "02/09/1987" ""] ["comp.sources.unix" "11" "v11i036" 293 "test.el" 3 "\"Mark A. Ardis\" " "Test system for GNU Emacs" "" "10/09/1987" ""] :EOTB ;;; forms-demo2-inherent.edb ends here edb-1.31/examples/forms-demo2-int.dat0000644000175000017500000000215710745370011015621 0ustar ttnttn;; Database file written by EDB; format 0.7 ["Public Domain Software Archive" [arch-newsgroup arch-volume arch-issue arch-article arch-shortname arch-parts arch-from arch-longname arch-keywords arch-date arch-remarks] [string string string integer string integer string string string string string] (((arch-shortname))) [nil nil nil "\n" nil nil nil nil nil nil] [nil nil nil " " nil nil nil nil nil nil] nil nil " " "" (("\n" . " ")) nil] ((:format-file . "forms-demo2.fmt")) ["comp.sources.unix" "" "v11i008" 269 "getty-enable" 1 "tron@sc.nsc.com (Ronald S. Karr)" "Getty on/off programs for 4.[23] BSD" "" "890505" "This program can be used to dynamically enable / disable terminal\nlines on a BSD system.\n"] ["comp.sources.unix" "11" "v11i022" 283 "syslog" 1 "emory!arnold (Arnold D. Robbins {EUCC})" "Development version of syslog(3), for ATT, too" "" "28/08/1987" ""] ["comp.sources.unix" "11" "v11i033" 290 "less3" 3 "sun!intsc!convgt!mark" "The 'less' pager" "" "02/09/1987" ""] ["comp.sources.unix" "11" "v11i036" 293 "test.el" 3 "\"Mark A. Ardis\" " "Test system for GNU Emacs" "" "10/09/1987" ""] edb-1.31/examples/forms-demo2.dat0000644000175000017500000000106510745370011015026 0ustar ttnttncomp.sources.unix v11i008 269 getty-enable 1 tron@sc.nsc.com (Ronald S. Karr) Getty on/off programs for 4.[23] BSD 890505 This program can be used to dynamically enable / disable terminal lines on a BSD system. comp.sources.unix 11 v11i022 283 syslog 1 emory!arnold (Arnold D. Robbins {EUCC}) Development version of syslog(3), for ATT, too 28/08/1987 comp.sources.unix 11 v11i033 290 less3 3 sun!intsc!convgt!mark The 'less' pager 02/09/1987 comp.sources.unix 11 v11i036 293 test.el 3 "Mark A. Ardis" Test system for GNU Emacs 10/09/1987 edb-1.31/examples/forms-demo2.edb0000444000175000017500000000331710745370011015010 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "Public Domain Software Archive" :fields [arch-newsgroup arch-volume arch-issue (arch-article . integer) arch-shortname (arch-parts . integer) arch-from arch-longname arch-keywords arch-date arch-remarks] :field-order [arch-shortname] :summary-format "\\arch-shortname - \\arch-longname\n [\\arch-parts parts]" :substitutions [("\n" . "\C-k")] :display t ====== Public Domain Software Archive ====== \arch-shortname - \arch-longname Article: \arch-newsgroup/\arch-article Issue: \arch-issue Date: \arch-date Submitted by: \arch-from Keywords: \arch-keywords Parts: \arch-parts ====== Remarks ====== \arch-remarks :EOTB :report t Short name: \arch-shortname Long name: \arch-longname Article \arch-article in issue \arch-issue of \arch-newsgroup, appeared \arch-date :EOTB ;;; forms-demo2.edb ends here edb-1.31/examples/forms-demo2.fmt0000444000175000017500000000150610745370011015042 0ustar ttnttn====== Public Domain Software Archive ====== \arch-shortname - \arch-longname Article: \arch-newsgroup/\arch-article Issue: \arch-issue Date: \arch-date Submitted by: \arch-from Keywords: \arch-keywords Parts: \arch-parts ====== Remarks ====== \arch-remarks Local Variables: eval: (database-set-fieldnames-to-list database '(arch-newsgroup arch-volume arch-issue (arch-article . integer) arch-shortname (arch-parts . integer) arch-from arch-longname arch-keywords arch-date arch-remarks)) eval: (setf (database-print-name database) "Public Domain Software Archive" (database-field-priorities database) '(((arch-shortname))) (database-substitutions database) '(("\n" . "\C-k"))) eval: (dbf-set-summary-format "\\arch-shortname - \\arch-longname\n [\\arch-parts parts]") End: edb-1.31/examples/forms-demo2.report0000444000175000017500000000021410745370011015562 0ustar ttnttn Short name: \arch-shortname Long name: \arch-longname Article \arch-article in issue \arch-issue of \arch-newsgroup, appeared \arch-date edb-1.31/examples/geneal0000444000175000017500000000601510745370011013356 0ustar ttnttnDate: Fri, 24 Jul 92 21:28:05 EDT To: edb-list@theory.lcs.mit.edu Subject: Elaborate example of EDB use (Genealogy) From: Michael A. Patton I'm releasing my genealogy database front-end for EDB as example code. I've been using it for a little while now, developing it in parallel with the main EDB development. The "external" format is intended for use with a free program called Geneal (which I'm also working on). It has a number of interesting features that other EDB users may find useful for reference... o _Not_ written by Mike Ernst, the convolutions of my brain being different, it may offer suggestions on different ways of doing things. o Very elaborate use of the db-tagged external format (this is what I wrote it for :-) o Actual database is a network, not strictly a linear list of records. There are fields in the database which are "references" to other records (these are also always paired, i.e. the target will have a [predictable] pointer back). In the internal form, these fields contain the actual referenced record. o Several special purpose types, for the above "references", and lists thereof. These also have multiple variant display functions, so a reference can show as both the internal record number and as some text derived from the referenced record (for genealogy, the referenced person's name :-). o Special commands to move from record to record via these "references", including options to create new records if needed and provide the appropriate bidirectional links. o Fields which are "computed", i.e. not actually stored in the DB but calculated internally from other data when needed and cached in the internal form. o Variant records (although the handling is still a bit of a kludge). The database actually consists of 4 different kinds of records which have different fields (the kludge being that the rep is a superset of these). It uses the alternate-format features to get different displays with only the relevant fields for editing in each record. o No documentation :-) To get a copy, use anonymous FTP to FTP.LCS.MIT.EDU and look in the directory ~map/genealogy (~map/genealogy.tar.Z is the obvious compilation thereof), all the files there are related, the main code is in geneal.el, there are five format (.fmt) files and an example data file. You will need EDB version 0.29 for it to run. I've only done the most rudimentary robustness pass at this, and fixed bugs I came across while using it to maintain my own genealogy DB. I'll be happy to hear feedback on it from anyone who wants to. I'd especially appreciate cleanup of some of the EDB interface stuff (it's pretty haphazard since I was writing it as EDB was developing). __ /| /| /| \ Michael A. Patton, Network Manager / | / | /_|__/ Laboratory for Computer Science / |/ |/ |atton Massachusetts Institute of Technology Disclaimer: The opinions expressed above are a figment of the phosphor on your screen and do not represent the views of MIT, LCS, or MAP. :-) edb-1.31/examples/geneal.dat0000644000175000017500000004255310745370011014136 0ustar ttnttn0 Description of data format :Data file for genealogy records. :This is a sample file which shows what the data file format should :be like. :The information in this sample file is believed to be true; :William Harris Crawford is a great-great-great-grandfather of the Author. : :File format: :Each record specifies either an individual or a family. :Each record has a unique index number. :Each record is separated by a blank line. :Each line within a record is an item of data (except multi-line, see below). :Each item of data consists of a key, a colon, and a payload string. :Lines which start with a colon are comment lines. :Lines which start with a plus mark (+) are data continuation lines which : allow multi-line payload strings. :The first line of each record starts with an integer which is :the index number for that record. The rest of that line is ignored. :In this file, by convention (not enforced by the software), the first :digit of the record number can be used to determine the type of record: : 1 Individual : 2 Family : 3 Address : 4 Reference : :The fields used in this file are described here: :T:Type of record: : I for individual, F for family, A for address, R for reference : :Fields in an individual record: :LN:Last (born) name (family name) :LN.A:Adopted last name (typically through marriage) :FN:First name :MN:Middle names :NN:Nickname :PN:Prefix name (Dr., Lord, King, etc.) :SN:Suffix name (Jr., Sr., Esq., R.N., etc.) :SX:Sex (M or F) :B:Birthdate in the format dd-mmm-yyyy :BP:Place of birth :D:Date of death in the same format :DP:Place of death :BUR:Burial place :P:Index number of parent's marriage :S:List of index numbers of marriages :ADDR:record number of addr for this record :SOURCE:Source for the information in this record (e.g. reference number) : :A family record contains information about a marriage and its offsprings. :Fields in a family record: :N:family name :H:Index number of husband :W:Index number of wife :M:Date of marriage :MD:Date of end of marriage :MP:Place of marriage :MDP:Place of end of marriage :C:Index number list of children from this marriage :ADDR:record number of addr for this record : :Fields in an address record: :WHO:record number for the I or F record this addr applies to :ADDR:The address :PHONE:Telephone : :Fields in a reference record: :(not yet defined) : :General fields: :EDITED:date the record was last edited (this field added 26.Oct.87, so : records edited last before that date do not have this field) :TNOTE:a note which can be output in family trees (may be multi-line) :GEN:General information of interest about that person. :TGEN:Things which are both TNOTE and GEN. :COM:Comments (these do not appear in family pages or trees). : :first real record follows :(the numbers are not consecutive because this database represents :only a selected portion of the Author's entire database.) 1297 William Harris Crawford (1772) T:I LN:Crawford FN:William MN:Harris SX:M B:24-Feb-1772 BP:Amherst Co., VA D:15-Sep-1834 DP:Elberton, Oglethorpe Co., GA BUR:Woodlawn (3 miles west of Lexington, GA), + near Crawford, Oglethorpe Co., GA P:2093 S:2092 TNOTE:Moved w father to Edgefield dist. SC in 1779, +then to Columbia Co., GA in 1783. +Senator; see encyclopedia GEN:Written up in most encyclopedias. +6th child SOURCE:Mary Burgess Burnaugh;Encyclopedia Brittanica 1298 Susanna Gerardin Crawford T:I LN:Gerardin LN.A:Crawford FN:Susanna SX:F S:2092 TNOTE:Huguenot descent GEN:of Huguenot descent SOURCE:Mary Burgess Burnaugh 1299 Joel Crawford (1736) T:I LN:Crawford FN:Joel SX:M B:1736 BP:Hanover Co., VA D:1788 P:2094 S:2093 GEN:6th child SOURCE:Mary Burgess Burnaugh 1300 Francis Harris Crawford T:I LN:Harris LN.A:Crawford FN:Francis NN:Fanny SX:F S:2093 P:2099 SOURCE:Mary Burgess Burnaugh 1301 David Crawford (1697) T:I LN:Crawford FN:David SX:M B:1697 BP:Hanover Co., VA D:1766 P:2095 S:2094 GEN:5th child SOURCE:Mary Burgess Burnaugh 1302 Ann Anderson Crawford (1708) T:I LN:Anderson LN.A:Crawford FN:Ann SX:F B:1708 D:1803 S:2094 SOURCE:Mary Burgess Burnaugh 1303 Capt. David Crawford (1662) T:I LN:Crawford FN:David PN:Capt. SX:M B:1662 D:1762 P:2096 S:2095 TNOTE:of Amherst Co., VA GEN:Lived to be over 100 SOURCE:Mary Burgess Burnaugh 1304 Elizabeth Smith Crawford (1665) T:I LN:Smith LN.A:Crawford FN:Elizabeth SX:F B:1665 D:1766 S:2095 TNOTE:of Hanover Co., VA GEN:Lived to be over 100 SOURCE:Mary Burgess Burnaugh 1305 David Crawford (1625) T:I LN:Crawford FN:David SX:M B:1625 BP:Ayrshire, Scotland P:2097 S:2096 TNOTE:Imm 1643 from Scotland to VA GEN:Immigrated to Virginia from Scotland in 1643 SOURCE:Mary Burgess Burnaugh 1306 John, Earl of Crawford (1600) T:I LN:Crawford FN:John NN:Earl of Crawford SX:M B:1600 BP:Ayrshire, Scotland D:1676 S:2097 TNOTE:Imm 1643 from Scotland to Jamestown, VA +Died in Bacon Rebellion GEN:Immigrated to Jamestown, VA, from Scotland in 1643 +Died fighting in the Bacon Rebellion in Virginia SOURCE:Mary Burgess Burnaugh 1311 Maj. Robert Harris T:I LN:Harris FN:Robert PN:Maj. SX:M S:2099 P:2100 SOURCE:Mary Burgess Burnaugh 1312 Mouring Glenn T:I LN.A:Harris LN:Glenn FN:Mourning SX:F S:2099 SOURCE:Mary Burgess Burnaugh (had LN=Glen) SOURCE:Genealogy of Virginia Families 1313 William Harris T:I LN:Harris FN:William PN:Capt. SX:M S:2100 P:2101 SOURCE:Mary Burgess Burnaugh SOURCE:Genealogy of Virginia Families 1314 Temperance Overton Harris T:I LN.A:Harris LN:Overton FN:Temperance SX:F B:1679 D:1716 P:2102 S:2100 TGEN:of Hanover Co., VA SOURCE:Mary Burgess Burnaugh SOURCE:Genealogy of Virginia Families (dates) 1315 Maj. Robert Harris T:I LN:Harris FN:Robert PN:Maj. SX:M S:2101 P:2103 SOURCE:Mary Burgess Burnaugh 1316 Mary Claiborne Harris T:I LN.A:Harris LN:Claiborne FN:Mary SX:F P:2106 S:2101 SOURCE:Mary Burgess Burnaugh 1317 William Overton (1628) T:I LN:Overton FN:William SX:M B:1628 BP:England P:2114 S:2102 TNOTE:prob. a soldier for Bacon SOURCE:Mary Burgess Burnaugh 1318 Mary Waters Overton T:I LN.A:Overton LN:Waters FN:Mary SX:F S:2102 SOURCE:Mary Burgess Burnaugh 1319 Capt. Thomas Harris T:I LN:Harris FN:Thomas PN:Capt. SX:M B:1585 or 6 D:post 1647 P:2109 S:2103 TNOTE:Imm May-16(11?) in "Prosperous" GEN:Immigrated May-16(11?) in the "Prosperous" +Settled in Henrico Co., VA, 1611 +Wrote a will 2-Jun-1679 +Member Virginia Company, 1609 SOURCE:(Mary Burgess Burnaugh) SOURCE:Genealogy of Virginia Families 1320 Adria Gurganey Harris T:I LN.A:Harris LN:Gurganey FN:Adria SX:F B:1597/8 S:2103 TNOTE:Imm Nov-1621 in "Marmaduke" GEN:Immigrated Nov-1621 in the "Marmaduke" SOURCE:(Mary Burgess Burnaugh said Osborne) SOURCE:Genealogy of Virginia Families 1321 Thomas Osborne T:I LN:Osborne FN:Thomas SX:M S:2104 D:post 1633 TNOTE:Imm Nov-1619 in "Bona Nova" TNOTE:Immigrated Nov-1619 in the "Bona Nova" COM:(Mary says:)Settled in Henrico Co., VA, 1611 SOURCE:Mary Burgess Burnaugh 1333 Secy. William Claiborne (ca 1600) T:I LN:Claiborne FN:William PN:Secy. SX:M B:baptized 10-Aug-1600 BP:Crayford, Kent Co., England D:ca. 1676 DP:Virginia P:2112 S:2106 SOURCE:Genealogy of Virginia Families TNOTE:Imm. 1621 to VA w Gov. Sir Frances Wyatt +Secretary of Virginia; See encyclopedia GEN:Immigrated to Virginia in 1621 with Governer Sir Francis Wyatt. +Appointed Secretary of State of Virginia in 1625. 1334 Elizabeth Butler Claiborne (ca 1610) T:I LN:Butler LN.A:Claiborne FN:Elizabeth SX:F B:pre 1612 (ca. 1610?) BP:prob. England D:post 1668 DP:Virginia P:2113 S:2106 SOURCE:Genealogy of Virginia Families 1335 Lt. Col. William Claiborne (ca. 1636) T:I LN:Claiborne FN:William PN:Lt. Col. SX:M B:ca. 1636 D:1682 P:2106 TGEN:Officer against Bacon's Rebellion SOURCE:Genealogies of Virginia Families 1336 Col. Thomas Claiborne T:I LN:Claiborne FN:Thomas PN:Col. SX:M B:17-Aug-1647 D:7-Oct-1683 BUR:Romancoke, King William Co., VA P:2106 SOURCE:Genealogy of Virginia Families 1337 William Overton T:I LN:Overton FN:William SX:M B:1675 P:2102 SOURCE:Genealogy of Virginia Families 1338 Capt. James Overton T:I LN:Overton FN:James PN:Capt. SX:M B:1686 P:2102 SOURCE:Genealogy of Virginia Families 1339 Benjamin Harris T:I LN:Harris FN:Benjamin SX:M D:(will probated 1765) P:2100 SOURCE:Genealogy of Virginia Families 1340 Frederick Harris T:I LN:Harris FN:Frederick SX:M B:1705 P:2100 S:2107 SOURCE:Genealogy of Virginia Families 1341 Keziah Harris Nelson T:I LN:Harris LN.A:Nelson FN:Keziah SX:F P:2107 S:2108 SOURCE:Genealogy of Virginia Families 1342 Fanny Overton T:I LN:Overton LN.A:Harris SX:F S:2107 SOURCE:Genealogy of Virginia Families 1343 James Nelson T:I LN:Nelson FN:James SX:M B:1723 S:2108 SOURCE:Genealogy of Virginia Families 1344 Lucy Harris T:I LN:Harris FN:Lucy SX:F P:2099 SOURCE:Genealogy of Virginia Families 1345 Elizabeth Harris T:I LN:Harris FN:Elizabeth SX:F P:2100 SOURCE:Genealogy of Virginia Families 1346 Mary Overton T:I LN:Overton FN:Mary SX:F D:1735 P:2102 SOURCE:Genealogy of Virginia Families 1347 Jane Claiborne T:I LN:Claiborne FN:Jane SX:F P:2106 SOURCE:Genealogy of Virginia Families 1348 Mary Harris (1625) T:I LN:Harris FN:Mary SX:F B:1625 D:1-Feb-1703(4) (will probated) P:2103 SOURCE:Genealogy of Virginia Families 1349 Thomas Harris T:I LN:Harris FN:Thomas SX:M D:will written 2-Jun-1679 P:2103 SOURCE:Genealogy of Virginia Families 1350 Maj. William Harris T:I LN:Harris FN:William PN:Maj. SX:M D:1677 P:2103 TNOTE:"Killed by the Inidians" SOURCE:Genealogy of Virginia Families 1351 Sir William Harris T:I LN:Harris FN:William PN:Sir SX:M S:2109 TNOTE:Desc from Sir Thomas Percy GEN:Descended from Sir Thomas Percy SOURCE:Genealogy of Virginia Families 1352 Sir Thomas Smith T:I LN:Smith FN:Thomas PN:Sir SX:M P:2110 TNOTE:Treas. Virginia Co +Gov. East India Co GEN:Treasurer of the Virginia Company +Governer of the East India Company SOURCE:Genealogy of Virginia Families 1353 (?) Smith T:I LN:Smith LN.A:Harris SX:F P:2110 S:2109 SOURCE:Genealogy of Virginia Families 1354 "Customer" Smith T:I LN:Smith FN:"Customer" SX:M S:2110 SOURCE:Genealogy of Virginia Families 1355 (?) Judd T:I LN:Judd LN.A:Smith SX:F P:2111 S:2110 SOURCE:Genealogy of Virginia Families 1356 Sir Andrew Judd T:I LN:Judd FN:Andrew PN:Sir SX:M S:2111 TGEN:Lord Mayor SOURCE:Genealogy of Virginia Families 1357 Sarah Harris (1736) T:I LN:Harris FN:Sarah SX:F B:24-May-1736 D:31-Jan-1803 P:2099 SOURCE:Genealogy of Virginia Families 1358 Mary Crawford (1703) T:I LN:Crawford FN:Mary SX:F B:Mar-1703 P:2095 SOURCE:Genealogy of Virginia Families 1359 Gen. Robert Overton T:I LN:Overton FN:Robert PN:Gen. SX:M S:2114 TNOTE:of Cromwellian Army SOURCE:Genealogy of Virginia Families 1360 Thomas Claiborne (1599) T:I LN:Claiborne FN:Thomas SX:M B:baptized 25-Jul-1599 BP:Middlesex, England D:1633 P:2112 SOURCE:Genealogy of Virginia Families 1361 Sara Claiborne (1601/2) T:I LN:Claiborne FN:Sara SX:F B:baptized 7-Mar-1601/2 BP:Crayford, Kent Co., England P:2112 SOURCE:Genealogy of Virginia Families 1362 Katherine Claiborne (1603) T:I LN:Claiborne FN:Katherine SX:F B:baptized 30-Mar-1603 BP:Crayford, Kent Co., England P:2112 SOURCE:Genealogy of Virginia Families 1363 Blanche Claiborne (1605) T:I LN:Claiborne FN:Blanche SX:F B:baptized 5-Sep-1605 BP:Crayford, Kent Co., England P:2112 SOURCE:Genealogy of Virginia Families 1364 John Butler (1600) T:I LN:Butler FN:John PN:Capt. SX:M B:baptized 7-Dec-1600 BP:Roxwell, Essex Co., England D:will proved 1-Jul-1642 DP:Maryland P:2113 SOURCE:Genealogy of Virginia Families 1365 Thomas Butler T:I LN:Butler FN:Thomas SX:M P:2113 TNOTE:of London SOURCE:Genealogy of Virginia Families 1366 Jane Butler T:I LN:Butler FN:Jane SX:F P:2113 SOURCE:Genealogy of Virginia Families 1367 Sarah Butler T:I LN:Butler FN:Sarah SX:F P:2113 SOURCE:Genealogy of Virginia Families 1368 Cressid Butler T:I LN:Butler FN:Cressid SX:F B:baptized 25-Jun-1612 P:2113 SOURCE:Genealogy of Virginia Families 1369 Martha Butler T:I LN:Butler FN:Martha SX:F B:post 1612 P:2113 SOURCE:Genealogy of Virginia Families 1370 Ursula Butler T:I LN:Butler FN:Ursula SX:F B:post 1612 P:2113 SOURCE:Genealogy of Virginia Families 1371 Jane Elliot (1576) T:I LN:Elliot LN.A:Butler FN:Jane SX:F B:baptized 22-Jun-1576 BP:Roxwell, Essex Co., England P:2116 S:2113 SOURCE:Genealogy of Virginia Families 1372 Edward Elliot T:I LN:Elliot FN:Edward SX:M S:2116 SOURCE:Genealogy of Virginia Families 1373 John Boteler T:I LN:Boteler FN:John SX:M P:2115 S:2113 TNOTE:of Littell Burch Hall, +Roxwell, Essex Co., England SOURCE:Genealogy of Virginia Families 1374 John Butler T:I LN:Butler FN:John SX:M D:will proved 20-Jan-1613 DP:London S:2115 SOURCE:Genealogy of Virginia Families 1375 Cressitt St. John T:I LN:St. John LN.A:Boteler FN:Cressitt SX:F P:2117 S:2115 SOURCE:Genealogy of Virginia Families 1376 Sir John St. John T:I LN:St. John FN:John PN:Sir SX:M S:2117 SOURCE:Genealogy of Virginia Families 1377 Sara Smith T:I LN:Smith LN.A:Claiborne FN:Sara SX:F D:1626 DP:Surrey, England P:2119 S:2112 SOURCE:Genealogy of Virginia Families 1378 Thomas Clayborne (1557) T:I LN:Clayborne FN:Thomas SX:M B:ca. 1557? D:buried 10-Sep-1607 P:2118 S:2112 BUR:Crayford, Kent Co., England SOURCE:Genealogy of Virginia Families 1379 Dorothy Clayborne T:I LN:Clayborne FN:Dorothy SX:F D:post 1588 P:2118 SOURCE:Genealogy of Virginia Families 1380 Katherine Clayborne T:I LN:Clayborne FN:Katherine SX:F P:2118 SOURCE:Genealogy of Virginia Families 1381 Joane Clayborne T:I LN:Clayborne FN:Joane SX:F P:2118 B:baptized 24-Jun-1560 D:buried 29-Sep-1575 SOURCE:Genealogy of Virginia Families 1382 Thomas Cleyborne (ca. 1525-30) T:I LN:Cleyborne FN:Thomas SX:M S:2118 B:ca. 1525-30? D:buried 7-Dec-1581 TNOTE:Mayor of King's Lynn, England SOURCE:Genealogy of Virginia Families 1383 John Smith T:I LN:Smith FN:John SX:M S:2119 D:will proved 15-Jan-1591/2 TNOTE:of Southwark, Surrey, England SOURCE:Genealogy of Virginia Families 1384 (Katherine) (?) Clayborne T:I LN.A:Clayborne FN:prob. Katherine SX:F S:2118 SOURCE:Genealogy of Virginia Families 1385 Leonard Claiborne T:I LN:Claiborne FN:Leonard SX:M D:1694 DP:Jamaica P:2106 SOURCE:Genealogy of Virginia Families 2092 William Crawford and Susanna Gerardin (1804) T:F N:Crawford H:1297 W:1298 M:28-Apr-1804 MP:(probably in Georgia) GEN:Eight children SOURCE:Mary Burgess Burnaugh ADDR:3000 :(bogus ADDR just as an example) 2093 Joel Crawford and Francis Harris (1760) T:F N:Crawford H:1299 W:1300 M:1760 MP:Amherst Co., VA C:1297 GEN:Moved to Edgefield Co., South Carolina, in 1779 +Moved to Columbia, Georgia, in 1783 SOURCE:Mary Burgess Burnaugh 2094 David Crawford and Ann Anderson (1727) T:F N:Crawford H:1301 W:1302 M:1727 C:1299 TNOTE:Moved to Amherst Co., VA in 1750 GEN:Moved to Amherst Co., VA in 1750 SOURCE:Mary Burgess Burnaugh 2095 Capt. David Crawford and Elizabeth Smith (1695) T:F N:Crawford H:1303 W:1304 M:1695 C:1301,1358 SOURCE:Mary Burgess Burnaugh 2096 David Crawford and ?? (1654) T:F N:Crawford H:1305 M:1654 MP:Virginia C:1303 SOURCE:Mary Burgess Burnaugh 2097 John "Earl of" Crawford and ?? (ca. 1620)) T:F N:Crawford H:1306 C:1305 SOURCE:Mary Burgess Burnaugh 2099 Maj. Robert Harris and Mourning Glenn T:F N:Harris H:1311 W:1312 C:1300,1344,1357 SOURCE:Mary Burgess Burnaugh 2100 William Harris and Temperance Overton T:F N:Harris H:1313 W:1314 M:1695 C:1311,1339,1340,1345 SOURCE:Mary Burgess Burnaugh SOURCE:Genealogy of Virginia Families (M) 2101 Maj. Robert Harris and Mary Claiborne T:F N:Harris H:1315 W:1316 C:1313 SOURCE:Mary Burgess Burnaugh 2102 William Overton and Mary Waters T:F N:Overton H:1317 W:1318 M:1670 MP:England C:1337,1314,1338,1346 TNOTE:Imm. "soon after" 1670 SOURCE:Mary Burgess Burnaugh SOURCE:Genealogy of Virginia Families 2103 Capt. Thomas Harris and Adria T:F N:Harris H:1319 W:1320 C:1349,1350,1315,1348 TNOTE:Married before immigrating SOURCE:Mary Burgess Burnaugh 2104 Thomas Osborne and ?? T:F N:Osborne H:1321 SOURCE:Mary Burgess Burnaugh 2106 William Claiborne and Elizabeth Butler T:F N:Claiborne H:1333 W:1334 M:ca. 1635 MP:England C:1335,1336,1316,1347,1385 SOURCE:Genealogy of Virginia Families 2107 Frederick Harris and Fanny Overton T:F N:Harris H:1340 W:1342 C:1341 SOURCE:Genealogy of Virginia Families 2108 James Nelson and Keziah Harris T:F N:Nelson H:1343 W:1341 M:1750 MP:Hanover Co., VA SOURCE:Genealogy of Virginia Families 2109 Sir William Harris and (?) Smith T:F N:Harris H:1351 W:1353 C:1319 SOURCE:Genealogy of Virginia Families 2110 "Customer" Smith and (?) Judd T:F N:Smith H:1354 W:1355 C:1352,1353 SOURCE:Genealogy of Virginia Families 2111 Sir Andrew Judd and (?) T:F N:Judd H:1356 C:1355 SOURCE:Genealogy of Virginia Families 2112 Thomas Clayborne and Sara Smith (1598) T:F N:Claiborne H:1378 W:1377 M:21-Nov-1598 MP:Middlesex Co., England C:1360,1333,1361,1362,1363 SOURCE:Genealogy of Virginia Families 2113 John Boteler and Jane Elliot (1599) T:F N:Butler H:1373 W:1371 M:27-Dec-1599 MP:Roxwell, Essex Co., England C:1364,1365,1366,1367,1334,1368,1369,1370 TNOTE:Sometimes "Boteler" SOURCE:Genealogy of Virginia Families 2114 Gen. Robert Overton and (?) T:F N:Overton H:1359 C:1317 SOURCE:Genealogy of Virginia Families 2115 John Butler and Cressitt St. John T:F N:Boteler H:1374 W:1375 C:1373 SOURCE:Genealogy of Virginia Families 2116 Edward Elliot and (?) T:F N:Elliot H:1372 C:1371 SOURCE:Genealogy of Virginia Families 2117 Sir John St. John and (?) T:F N:St. John H:1376 C:1375 SOURCE:Genealogy of Virginia Families 2118 Thomas Cleyborne and Katherine (?) T:F N:Clayborne H:1382 W:1384 C:1378,1379,1380,1381 SOURCE:Genealogy of Virginia Families 2119 John Smith and (?) T:F N:Smith H:1383 C:1377 SOURCE:Genealogy of Virginia Families 3000 sample (bogus) address T:A WHO:2092 ADDR:Woodlawn +Lexington, Georgia PHONE:(101)555-1212 0 :end of file edb-1.31/examples/geneal.edb0000444000175000017500000007125010745370011014112 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2006,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; This was written based on files in the genealogy package ;; by Michael A. Patton , and is able to handle ;; the file geneal.dat (taken unabridged from that package), with ;; some caveats: ;; ;; - There are two records with index 0 (zero) in geneal.dat! ;; Strict checking would reject this, but we're not strict... ;; ;; - The `record-description' field (tag DESC) is redundant but ;; not completely replaceable by `geneal-set-description'. ;; ;; - To avoid using `db-view-mode-hooks', which will probably go ;; away in the future, you need to call `geneal-install-keymap' ;; manually one time (at most). Presently, there is no way ;; to undo its effect (i.e., no "geneal-uninstall-keymap"). ;; ;; - (Style Note) The display formats have been tweaked only ;; slightly from those found in the original package. They ;; probably could use a little redesign/cleanup. ;; ;; - Adding and deleting records has not yet been tested. ;;; Code: (require 'cl) (require 'db-tagged) (require 'edb-t-timedate1) (defconst geneal-tags '(((index . record-index) "INDEX" "The identifying index for this record") (record-description "DESC" "A short summary of the record") ((type . geneal-record-type) "T" "Record type, one of: IFAR") ;; Name specification (name "N" "Name") (prefix-name "PN" "Prefix name (e.g. \"Dr.\")") (first-name "FN" "First Name") (middle-name "MN" "Middle name") (nickname "NN" "Nickname") (last-name "LN" "Last Name") (last-name-a "LN.A" "Adopted last name (i.e. by marriage)") (suffix-name "SN" "Suffix name (e.g. K.B.E.)") ;; landmarks... (date-of-birth "B" "Date of Birth") (birth-place "BP" "Place of Birth") ((sex . sex) "SX" "Sex, either F or M") (date-of-death "D" "Date of death") (place-of-death "DP" "Place of death") (buried "BUR" "Location of burial") (date-married "M" "Date married") (place-married "MP" "Place married") (marriage-end-date "MD" "Date marriage ended (e.g. by divorce)") (marriage-end-place "MDP" "Place marriage ended") ;; Cross references ((parents . record-ref) "P" "Parent family record") ((husband . record-ref) "H" "Husband of the marriage") ((wife . record-ref) "W" "Wife of the marriage") ((children . record-ref-list) "C" "List of children of this marriage") ((marriage . record-ref-list) "S" "Marriage record(s)") ;; Miscellaneous typed data ;;((addr . string) "ADDR" ;; "Used both for pointer to A type record and as the actual address") (addr "ADDR" "Used both for pointer to A type record and as the actual address") ((addr-ptr . record-ref) nil "Reference to A record with address") (phone "PHONE" "") ((who . record-ref-list) "WHO" "Who this address belongs to") ;; Fields to hold additional descriptive text (gen "GEN" "General info??") (com "COM" "Comment") (comments "" "Comments") (tgen "TGEN" "Some kind of general notes") (tnote "TNOTE" "Some kind of notes") ;; Administrative fields (source "SOURCE" "Source of the info in this record") ((edited . date) "EDITED" "When the record was last edited"))) (defvar geneal-mode-map nil "Keymap for Genealogy Database mode.") :tagged-setup `(:fields ,geneal-tags ;; Set formatting for geneal databases... :tag-chars "A-Z." :separator-regexp ":" :separator-output ":" :continuation-regexp "\\+" :continuation-output "+" ;; Indexing. :index-function (lambda (database) ; compute index/graph (let ((ht (database-get-local 'quick database))) ;; index (db-maprecords (lambda (record) (puthash (db-record-field record 'index) record ht))) ;; graph (let ((fields (delq nil (mapcar (lambda (spec) (and (consp (car spec)) (memq (cdar spec) '(record-ref-list record-ref)) (caar spec))) geneal-tags))) v d) (db-maprecords (lambda (record) (dolist (field fields) (setq v (db-record-field record field) d (if (consp v) (mapcar 'geneal-deref v) (geneal-deref v))) (db-record-set-field record field d))))))) ;; Special hooks to handle the initial line. :pre-parse-thunk (lambda () ; make fake INDEX/DESC (save-excursion (insert "INDEX:") (skip-chars-forward "0-9") (delete-horizontal-space) (insert "\nDESC:"))) :pre-write-function (lambda (record) ; remember start of record (database-set-local 'io-state database (point))) :post-write-function (lambda (record) ; revert INDEX/DESC (goto-char (database-get-local 'io-state database)) (delete-char 6) (when (< 0 (length (db-record-field record 'record-description))) (end-of-line) (insert "\t") (delete-char 6)) (goto-char (point-max)))) :summary-format "\\index\t\t\\record-description" :choose-display (lambda (type addr addr-ptr) ;; Automatically choose the appropriate format for the current record. ;; Hackishly, we also cross set some fields... (flet ((upd () (when (and (null addr-ptr) (< 0 (length addr))) (dbf-this-record-set-field 'addr-ptr (db-string->integer addr))))) (case type (individual (upd) "individual") (family (upd) "family") (address "address") (reference "reference") (t "geneal")))) :first-change-function (lambda (&rest ignored) (dbf-this-record-set-field 'edited (let ((edb-t-timedate1:parse-date-default 'current-date)) (edb-t-timedate1:parse-date-string nil)))) :locals [(quick (make-hash-table :size 511 :test 'eq)) io-state] ;;; Displays :display (:name "individual") === Genealogy database === Record type: \type Record # \index [\record-description] Name: \prefix-name \first-name \middle-name (\nickname) \last-name \last-name-a, \suffix-name (Sex: \sex) Born: \date-of-birth in \birth-place Died: \date-of-death in \place-of-death (buried in \buried) Parents: \parents \parents,record-ref-name Marriage(s): \marriage Address: \addr-ptr \addr-ptr,record-ref-addr TNOTE: \tnote GEN: \gen TGEN: \tgen COM: \com ------------------------------------------------------------------------------- Source(s) of information in this record: \source Record last edited: \edited,date-iso,unreachable Comments: \comments :EOTB :display (:name "address") === Genealogy database === Record type: \type Record # \index [\record-description] Whose address is this: \who \addr Phone: \phone ------------------------------------------------------------------------------- Source(s) of information in this record: \source Record last edited: \edited,date-iso Comments: \comments :EOTB :display (:name "family") === Genealogy database === Record type: \type Record # \index [\record-description] Husband: \husband \husband,record-ref-name Wife: \wife \wife,record-ref-name Married \date-married in \place-married (ended \marriage-end-date in \marriage-end-place) Children: \children Address: \addr-ptr \addr-ptr,record-ref-addr ------------------------------------------------------------------------------- Source(s) of information in this record: \source Record last edited: \edited,date-iso,unreachable Comments: \comments :EOTB :display (:name "reference") === Genealogy database === Record type: \type Record # \index [\record-description] [ I haven't quite figured out what "R" records are for, so this is just a ] [ generic display format... ] --------------(Note that this display is designed for "I" records)------------- Name: \prefix-name \first-name \middle-name (\nickname) \last-name \last-name-a, \suffix-name (Sex: \sex) Born: \date-of-birth in \birth-place Died: \date-of-death in \place-of-death (buried in \buried) Parents: \parents \parents,record-ref-name Marriages: \marriage TNOTE: \tnote GEN: \gen TGEN: \tgen COM: \com --------------(Note that this display is designed for "F" records)------------- Husband: \husband \husband,record-ref-name Wife: \wife \wife,record-ref-name Married \date-married in \place-married (ended \marriage-end-date in \marriage-end-place) Children: \children --------------(Note that this display is designed for "A" records)------------- Whose address is this: \who \addr Phone: \phone ------------------------------------------------------------------------------- Source of information in this record: \source Record last edited: \edited,date-iso Comments: \comments :EOTB :display (:name "geneal") === Genealogy database === Record type: \type Record # \index [\record-description] [ This display was used because the type of data in this record is unknown. ] [ The sections below show the information in the various fields that might ] [ appear in certain types of records. ] Comments appearing in the record: \comments Source(s) of information in this record: \source Record last edited: \edited,date-iso,unreachable --------------(Note that this display is designed for "I" records)------------- Name: \prefix-name \first-name \middle-name (\nickname) \last-name \last-name-a, \suffix-name (Sex: \sex) Born: \date-of-birth in \birth-place Died: \date-of-death in \place-of-death (buried in \buried) Parents: \parents Marriage(s): \marriage TNOTE: \tnote GEN: \gen TGEN: \tgen COM: \com --------------(Note that this display is designed for "F" records)------------- Husband: \husband \husband,record-ref-name Wife: \wife \wife,record-ref-name Married \date-married in \place-married (ended \marriage-end-date in \marriage-end-place) Children: \children --------------(Note that this display is designed for "A" records)------------- Whose address is this: \who \addr Phone: \phone :EOTB ;;; Support functions (defun geneal-deref (ref &optional quick) "Return the record associated with REF, or nil if not found. If REF is either nil or a record, return it straight away. REF can also be a string (for now -- this will go away Real Soon Now)." (unless quick (setq quick (database-get-local 'quick dbc-database))) (if (or (null ref) (vectorp ref)) ref (let* ((not-found (list (list))) (index (if (integerp ref) ref (unless (stringp ref) (error "Invalid genealogy reference type: %S" ref)) (string-to-number ref))) (rv (gethash index quick not-found))) (unless (eq rv not-found) rv)))) ;;; General function to follow a reference (defun geneal-follow-reference (code inv typ arg) "Follow the reference from the current record in field CODE. If a new record is made to be the target of the reference, the back pointer should be in the field INV and the record should be of type TYP. Fourth argument ARG is interactive prefix arg from original command, nil (normal) means never create a new record, also used to indicate which element of a list reference should be followed (1 based). Return t if a new record was created, nil otherwise. This is so that the caller can know to fill in fields that can be deduced." (let ((r (dbf-displayed-record-field code)) (ridx (dbf-displayed-record-field 'index))) (cond ((null r) (when (null arg) (error "Reference not given in this record.")) ;; Make a new record of the right type (let* ((quick (database-get-local 'quick dbc-database)) (idx (1+ (dbf-displayed-record-field 'index))) plist) ;; Ensure index does not collide. (while (geneal-deref idx quick) (setq idx (1+ idx))) (setq r (db-make-record dbc-database (list ;; Use the right type. 'type typ ;; Pick an index ... 'index idx ;; ... and the inverse pointer. Don't use ;; `r' directly because that may be a modified, ;; but not yet committed, record. inv (geneal-deref ridx quick)))) ;; Set the pointer we were going to follow (dbf-displayed-record-set-field code r) ;; Now install it in DB (puthash idx r quick) (database-add-record r dbc-database '1+) (db-jump-to-record r) t)) ((listp r) (when (and (null arg) (= (length r) 1)) (setq arg 1)) (unless arg (error "Reference is a list, must give arg...")) (when (listp arg) (setq arg (car arg))) ;;user arg one based...nth is zero based (setq r (nth (1- arg) r)) (when (integerp r) (error "Referenced record not in database.")) (unless r (error "Not that many references in list.")) (db-jump-to-record r) nil) ((integerp r) (error "Referenced record not in database.")) (t (db-jump-to-record r) nil)))) ;;; Special commands... (defun geneal-goto-parent (arg) "Show parent's marriage entry." (interactive "P") (geneal-follow-reference 'parents 'children 'family arg)) (defun geneal-goto-husband (arg) "Show husband." (interactive "P") (when (geneal-follow-reference 'husband 'marriage 'individual arg) (dbf-displayed-record-set-field 'sex 'male)) (dbf-redisplay-entire-record-maybe)) (defun geneal-goto-wife (arg) "Show wife." (interactive "P") (when (geneal-follow-reference 'wife 'marriage 'individual arg) (dbf-displayed-record-set-field 'sex 'female)) (dbf-redisplay-entire-record-maybe)) (defun geneal-goto-marriage (arg) "Show marriage." (interactive "P") (geneal-follow-reference 'marriage (if (eq (dbf-displayed-record-field 'sex) 'male) 'wife 'husband) 'family arg)) (defun geneal-goto-child (arg) "Show child." (interactive "P") (geneal-follow-reference 'children 'parents 'individual arg)) (defun geneal-goto-reference (n) "Goto the genealogy record with index N. N can be given as prefix or prompted for." (interactive "NGoto reference number:") (let ((r (geneal-deref n))) (unless r (error "Record not in database.")) (db-jump-to-record r))) (defun geneal-change-record-index (n) "Change the index number of this record to N (as prefix or prompted for). All linked records will record the change as well." (interactive "NNew reference number:") (let* ((quick (database-get-local 'quick dbc-database)) (old-n (dbf-displayed-record-field 'index)) (rec (gethash old-n quick))) (unless (eq rec (dbf-displayed-record)) (error "Index table corrupted")) (when (gethash n quick) (error "Index already used in database")) (puthash n rec quick) (remhash old-n quick) (dbf-displayed-record-set-field 'index n) (dbf-redisplay-entire-record-maybe))) ;;; Description setting ... (defun geneal-set-description () "Set the summary description of this record from data in the record. This works for `individual' and `family' records; all other types signal error." (interactive) (let* ((rcd (dbf-displayed-record)) (typ (db-record-field rcd 'type)) (fun (case typ (individual 'geneal-individual-description) (family 'geneal-family-description) ;; Also consider 'address and 'reference (maybe). (t (error "Can't generate description of %s records" typ)))) (val (substring (funcall fun rcd) 1))) (dbf-displayed-record-set-field 'record-description val) (dbf-redisplay-entire-record-maybe))) (defun geneal-individual-description (rcd) (concat (flet ((maybe (pfx fld sfx) (let ((tmp (db-record-field rcd fld))) (and tmp (< 0 (length tmp)) (concat pfx tmp sfx))))) (concat (maybe " " 'prefix-name "") (maybe " " 'first-name "") (maybe " " 'middle-name "") (maybe " (" 'nickname ")") (maybe " " 'last-name "") (maybe " [" 'last-name-a "]") (maybe ", " 'suffix-name ""))) (let ((rx "^\\([-0-9a-z]+-\\)?\\([12]?[0-9][0-9][0-9]\\)\\((.+)\\)?$") b d) (setq b (db-record-field rcd 'date-of-birth) b (cond ((= 0 (length b)) nil) ((string-match rx b) (match-string 2 b)) (t b)) d (db-record-field rcd 'date-of-death) d (cond ((= 0 (length d)) nil) ((string-match rx d) (match-string 2 d)) (t d))) (cond ((and b d) (concat " (" b "-" d ")")) (b (concat " (b: " b ")")) (d (concat " (d: " d ")")) (t nil))))) (defun geneal-family-description (rcd) (flet ((full (r) (concat (db-record-field r 'first-name) " " (db-record-field r 'last-name))) (half (which) (let ((r (db-record-field rcd which))) (if r (full r) "(?)")))) (concat " " (half 'husband) " and " (half 'wife)))) ;;; Basic datatype record-index (edb-define-recordfieldtype 'record-index nil :type 'record-index :default-value nil :actual->stored 'number-to-string :stored->actual 'string-to-number :order-fn 'db-number-order :sort-fn '< :match-function '= :help-info "The index of a record in the database.") (edb-define-displaytype 'record-index nil :indent nil :reachablep nil :actual->display 'number-to-string :display->actual 'string-to-number) ;;; Basic datatype record-ref (edb-define-recordfieldtype 'record-ref nil :type 'record-ref :default-value nil :actual->stored 'geneal-record-ref->stored :stored->actual 'geneal-stored->record-ref :order-fn 'geneal-record-ref-order :sort-fn 'geneal-record-ref-< :match-function 'geneal-record-ref-= :help-info "A reference to another record in the database.") (defun geneal-record-ref-order (a b) "Return -1, 0, or 1 depending on whether the record A comes before B, is the same record as B, or comes after B. A nil reference always comes \"before\" any other." (cond ((and a b) ;; A and B both have some value, let's coerce to an int... (unless (integerp a) (setq a (db-record-field a 'index))) (unless (integerp b) (setq b (db-record-field b 'index))) ;; Now compare the indices (cond ((= a b) 0) ((< a b) -1) (t 1))) (a 1) (b -1) (t 0))) (defun geneal-record-ref-= (a b) "Return t if the records A and B are the same, nil otherwise." (= (geneal-record-ref-order a b) 0)) (defun geneal-record-ref-< (a b) "Returns t if the record A comes before B, nil otherwise. A nil reference always comes \"before\" any other." (< (geneal-record-ref-order a b) 0)) (defun geneal-record-ref->stored (ref) (cond ((integerp ref) (number-to-string ref)) (ref (number-to-string (db-record-field ref 'index))) (t nil))) (defun geneal-stored->record-ref (str) (cond ((null str) nil) ((integerp str) str) ((or (string-equal str "unknown") (string-equal str "")) nil) (t (db-string->integer str)))) ;;; Display types related to datatype record-ref ;;; Base display type just shows number...and allows update (edb-define-displaytype 'record-ref nil :indent nil :actual->display 'geneal-record-ref->string :display->actual 'geneal-string->record-ref) (defun geneal-record-ref->string (ref) (cond ((integerp ref) (number-to-string ref)) (ref (number-to-string (db-record-field ref 'index))) (t "Unknown"))) (defun geneal-string->record-ref (str) (cond ((null str) nil) ((or (string-equal str "unknown") (string-equal str "")) nil) ((integerp str) str) (t (db-string->integer str)))) ;;; Generic function to indirect through a reference (defun geneal-record-ref->value-generic (ref fld) (if (null ref) "" (let ((r (geneal-deref ref))) (if (null r) "[[[ No record in database ]]]" (db-record-field r fld))))) (defmacro define-geneal-record-ref-display (typ fld) `(edb-define-displaytype ,typ nil :indent t :max-height nil :reachablep nil :actual->display (lambda (ref) (geneal-record-ref->value-generic ref ,fld)) :display->actual 'geneal-no-edit)) ;;; Show the name of the referenced record (define-geneal-record-ref-display 'record-ref-name 'record-description) ;;; Show the address from the referenced record (define-geneal-record-ref-display 'record-ref-addr 'addr) ;;; Basic datatype record-ref-list ;;; A list of record-refs (int, nil or actual record), single elements ;;; are allowed to be represented without list... (edb-define-recordfieldtype 'record-ref-list nil :type 'record-ref-list :default-value nil :actual->stored 'geneal-record-ref-list->stored :stored->actual 'geneal-stored->record-ref-list :help-info "A list of references to other records in the database.") (defun geneal-record-ref-list->stored (ref) (cond ((null ref) nil) ((listp ref) (mapconcat 'geneal-record-ref->stored ref ",")) (t (geneal-record-ref->stored ref)))) (defun geneal-stored->record-ref-list (str) (cond ((null str) nil) ((integerp str) str) ((or (string-equal str "unknown") (string-equal str "")) nil) (t (delq 0 (mapcar 'string-to-number (split-string str ",")))))) (edb-define-displaytype 'record-ref-list nil ;; For now you can't edit this directly :indent t :max-height nil :reachablep nil :actual->display 'geneal-record-ref-list->string :display->actual 'geneal-string->record-ref-list) (defun geneal-record-ref-list->string (ref) (if (and ref (listp ref)) (let ((idx 0)) (mapconcat (function (lambda (r) (concat (number-to-string (setq idx (1+ idx))) ": " (geneal-record-ref->string r) "\t" (geneal-record-ref->value-generic r 'record-description)))) ref "\n")) (concat (geneal-record-ref->string ref) "\t" (geneal-record-ref->value-generic ref 'record-description)))) ;;; Datatype Record-type and related stuff (defvar geneal-record-types (mapcar (lambda (sym) (cons sym (capitalize (symbol-name sym)))) '(individual family address reference))) (edb-define-displaytype 'geneal-record-type nil :indent nil :reachablep nil :actual->display 'geneal-record-type->string :display->actual 'geneal-string->record-type) (edb-define-recordfieldtype 'geneal-record-type nil :type 'geneal-record-type :default-value nil :actual->stored 'geneal-record-type->stored :stored->actual 'geneal-stored->record-type :order-fn 'geneal-record-type-order :match-function 'eq :help-info "The type of a genealogy record.") (defun geneal-record-type->string (key) (if key (cdr (assq key geneal-record-types)) "Unspecified")) (defun geneal-string->record-type (key) (car (rassoc key geneal-record-types))) (defun geneal-record-type->stored (key) (and key (substring (cdr (assq key geneal-record-types)) 0 1))) (defun geneal-stored->record-type (key) (let ((c (aref key 0)) (l geneal-record-types) (r nil)) (while l (if (char-equal c (aref (cdar l) 0)) (setq r (caar l) l nil) (setq l (cdr l)))) r)) (defun geneal-record-type-order (a b) (cond ((eq a b) 0) ((eq a 'individual) -1) ((eq a 'family) (if (eq b 'individual) 1 -1)) ((eq a 'address) (if (eq b 'reference) -1 1)) ((eq a 'reference) 1))) ;;; Datatype sex ;;; The "sex" field can have three values, nil means unknown, and symbols ;;; male and female represent the obvious meanings... (defvar geneal-sex-alist '((male "Male") (female "Female"))) (edb-define-displaytype 'sex nil :indent nil :actual->display 'geneal-sex->string :display->actual 'geneal-string->sex) (edb-define-recordfieldtype 'sex nil :type 'sex :default-value nil :actual->stored 'geneal-sex->stored :stored->actual 'geneal-stored->sex :order-fn 'geneal-sex-order :match-function 'eq :help-info "The type of a genealogy record.") (defun geneal-sex->string (key) (if (null key) "Unspecified" (let ((l geneal-sex-alist) (r nil)) (while l (when (eq key (car (car l))) (setq r (cadr (car l)))) (setq l (cdr l))) r))) (defun geneal-string->sex (key) (let ((l geneal-sex-alist) (r nil)) (while l ;; Really want "initial substring..." (when (string-equal key (cadr (car l))) (setq r (car (car l)))) (setq l (cdr l))) r)) (defun geneal-sex->stored (key) (and key (let ((l geneal-sex-alist) (r nil)) (while l (when (eq key (car (car l))) (setq r (cadr (car l)))) (setq l (cdr l))) (substring r 0 1)))) (defun geneal-stored->sex (key) (let ((l geneal-sex-alist) (r nil)) (while l (when (string-equal key (substring (cadr (car l)) 0 1)) (setq r (car (car l)))) (setq l (cdr l))) r)) (defun geneal-sex-order (a b) (cond ((eq a b) 0) ((eq a 'male) -1) ((eq a 'female) 1))) ;;; Global stuff. (defun geneal-install-keymap (prefix) "Install a keymap w/ PREFIX char in the Database View mode keymap. \\{geneal-mode-map}" (interactive "cPrefix character for Genealogy commands: ") (unless geneal-mode-map (setq geneal-mode-map (let ((m (make-sparse-keymap))) (define-key m "p" 'geneal-goto-parent) (define-key m "h" 'geneal-goto-husband) (define-key m "w" 'geneal-goto-wife) (define-key m "m" 'geneal-goto-marriage) (define-key m "c" 'geneal-goto-child) (define-key m "g" 'geneal-goto-reference) (define-key m "n" 'geneal-change-record-index) (define-key m "d" 'geneal-set-description) m))) (define-key database-view-mode-map (char-to-string prefix) geneal-mode-map)) ;;; geneal.edb ends here edb-1.31/examples/intro-and-addr0000444000175000017500000005435210745370011014735 0ustar ttnttnHow to use EDB, the Emacs Database and print two column mailing labels ====================================================================== R. J. Chassell, bob@gnu.ai.mit.edu 10 March 1993 You need three Emacs Lisp packages: * The Emacs Database program by Michael Ernst * Two Column mode, by Daniel Pfeiffer * The `edb-format-addresses.el' file that I wrote, appended to this message. This file contains the following files near the end, following line feeds: sample.dat A sample data file with one record. addresses.fmt An addresses formatting file. addresses.lbl A formatting file for making labels edb-format-addresses.el An Emacs Lisp file for handling addresses. EDB and Two Column mode are available from: edb (1.09) 20-Jan-1993 Michael Ernst, archive.cis.ohio-state.edu: /pub/gnu/emacs/elisp-archive/packages/edb.tar.Z Customizable database program for Emacs; replaces forms editing modes two-column 14-May-1991 Daniel Pfeiffer, archive.cis.ohio-state.edu: /pub/gnu/emacs/elisp-archive/interfaces/two-column.el.Z Support for editing of a two-column text. Your .emacs file should contain the following: Be sure set your load path and use the right path names; these are for my own site. ;;;;;;;;;;;;;;;; for .emacs ;;;;;;;;;;;;;;;; ;;; Emacs Database, EDB ;; from Michael Ernst ;; 25 Nov 1991 ;; Be sure to specify the right directory for your system. (setq load-path (cons (expand-file-name "/u/edb") load-path)) (setq edb-directory "/u/edb") (autoload 'db-find-file "database" "EDB database package" t) (autoload 'load-database "database" "Load all the files of EDB, the Emacs database." t) ;;; Load EDB Update ;; Make it easy to install updates of EDB ;; 18 May 1992 (autoload 'edb-update "database" "EDB database package" t) (autoload 'edb-format-addresses "db-format-addresses" "Address label formatting" t) ;;; Two column mode ;; from Daniel Pfeiffer , ;; 14 May 1991 (autoload 'two-column "two-column" nil t) ;; Simplify typing the command (fset 'two-column 'two-column:split) ;; Set width for two-column mode (setq two-column:window-width 50) ;;;;;;;;;;;;;;;; end EDB and Two column entry for .emacs file ;;;;;;;;;; Three types of EDB file ======================= EDB uses three different kinds of file: * Data files. These contain the data and have a `.dat' extension to the file name. * Format files. These have a `.fmt' extension; these specify how the data appears on the screen, or in a summary. Usually, the screen display carries more information than a printing label. For example, the data includes telephone numbers. * Label files. These are also called `report files'. These contain the formatting commands for generating a printed address list. A label file contains only the formatting commands for printing the labels;it does not contain the formatting for displaying the telephone number or other information in the data file. Technically, a label file is just another format file, with different formatting commands. A label file may have either a `.fmt' extension or else some other extension. It is best to use `.lbl' so neither person nor machine confuses these files with format files. Using EDB: the basics ========= Change to the EDB directory and find a test file using the following command: M-x db-find-file RET filename.dat RET For example, the following command finds the sample addresses file: M-x db-find-file RET sample.dat RET EDB will read in the `.dat' data file and format the data for display on the screen according to the `.fmt' file of the same filename. (If you don't have a corresponding `.fmt' file, EDB will ask you for the name of the format file to use; in this case, the format file is `addresses.fmt'.) In EDB, in View mode, you can move from one file to another using `n' and `p'. View mode is read-only; you cannot edit in View mode. Change to Edit mode by typing `TAB'; this moves point into a field. Use TAB to move from one field to another. Change back to View mode from Edit mode by typing `C-c C-c'. In Edit mode, type `M-n', M-p' to go to next, prev record. In either mode, type `C-x C-s' to save changes you have made. In View mode, type `D' to create a summary. In View mode, type `q' to quit EDB temporarily; this command just buries the buffer; it does not offer to save. type `x' to exit EDB, offering to save changes. In either mode, type `C-h m' for a list of commands; or read the documentation. The sort feature is especially useful; for example, you can sort addresses by zip code, company, department, and name in that order. This means that all the people at one company site are in alphabetical order by name within each department. The sort feature is described in the documentation. Display ======= Here is the display for an on-screen database entry. See the `addresses.fmt' file at the end of this message for the actual file. Any field in this display can be blank. Customer Name Mail stop Department name Company name First address line Second address line City, State Zip code Telephone Date of last order Type (individual, company, university, etc.) Remarks The summary for this display format shows the following: company name, department, person's name, city, state The summary file is all on one line (the fields are truncated as necessary). The mailing labels contain only addresses. These are specified in the `addresses.lbl' format file (see the `addresses.lbl' file at the end of this message for the actual file.) Customer Name Mail stop Department name Company name First address line Second address line City, State Zip code Each address has seven lines, including the blank line that separates an address from the following address. The `addresses.fmt' and `addresses.lbl' files are appended to this file of instructions. The procedure below describes how to remove blank lines from within the body of each address and reinsert them at the end of the address. This way each printed label looks compact, but each each address continues to take exactly seven lines, so the printer prints each label in the right place. (You can adjust the number of lines per label.) A sample session is shown below after these explanations. The sample session spells out all the commands. How to make a mailing list ========================== Read in the database using the `M-x db-find-file' command (if prompted for an format file, type the file name, such as `addresses.fmt') Then type `r' to create a `report' file which contains the address labels. When prompted for a label format file, type the file name, for example, `addresses.lbl'. The `r' command creates a Text mode buffer with every record listed in the address label format. The buffer is called *Database Report* and is in Text mode, not EDB mode. The buffer is not yet a file; it is just a buffer. You have to save it to make it a file. How to remove blank lines from labels ===================================== Some addresses lack department names or have blank second address lines. You could print address labels with these blank lines, but the labels looks better if you remove them. The `m-x edb-format-addresses' command removes blank lines from the interior of an address and tacks them onto the end of the address. This way, each address continues to start N lines down, so you can use the list for printing sticky address labels To remove blank lines, visit the buffer containing the addresses list; this will be the *Database Report* buffer. If you have been following these instructions, you will already be visiting this buffer. Type M-x edb-format-addresses This command changes the buffer. Save the buffer as a file, for example, save it as `labels'. Now you have a single column file of addresses. The next step is to make a two column file, for printing on sticky address labels. (Read the documentation about the `forms-print-format-lines-adjust' variable in the `edb-format-addresses.el' file to see how to add blank lines to each address so each label takes up more or less space.) Two Column mode in Emacs. ======================== Two Column mode is a mode for writing text side by side; it is especially useful for people who write in both French and English, but it is also useful for creating two column address lists. How to make a two column label list from a one column list ========================================================== Go to the middle of the `labels' file. Type C-u 5 M-< to get to the exact middle of the buffer. ==> The sample data file included in this message contains ==> only one address; you will need to add more. Put the cursor on the first line of the closest address. This address is going to end up being the first label in the right hand column. The first label in the whole file will end up being the first label in the left hand column. Clip out all the text from point to the end of the buffer, using the `C-w' command. Type: C-w Enter two column mode by typing: M-x two-column RET (If `two-column' is not set with an `fset` command in your .emacs file, you will have to type the full name of the function: `two-column:split'.) Put point into the right hand window, and then yank the latter half of your address list buffer into the right hand side by using `C-y' command. Type: C-y Then merge the two columns: C-x 6 1 (You should use a 50 column wide window. If you do not set 50 columns in your .emacs file, you can set it with the following command: M-x set-variable RET two-column:window-width RET 50 RET After setting the window width, type `C-x 6 2' to regenerate two windows. You may want to try other widths, too.) Form feeds for printing ======================= Each page needs to start with a label at the top of the page. To do this, you need to insert form feeds in the right places. For seven line labels, you need to insert a form feed every 63 lines. You can either use a keyboard macro to do this or use the following elisp: (defun edb-sixty-three () "Insert Control-L every 63 lines." (interactive) (goto-char (point-min)) (while (not (eobp)) (next-line 63) (insert ?\C-l) (insert ?\n))) This function is in the `edb-format-addresses.el' file, so you should be able to run it by typing M-x edb-sixty-three (Note that sixty-three lines is for an address's spacing of either 7 or 9 lines; set `forms-print-format-lines-adjust' to a different number for different spacing.) Save file and then print it. ================================================================ Here is a Sample session: ============== After changing to your EDB directory and entering Emacs, read in the database file: M-x db-find-file RET sample.dat RET (Specify `addresses.fmt' as the format file.) ==> The sample data file included in this message contains ==> only one address; you will need to add more. Create a label buffer using addresses format: r RET addresses.lbl Clean up addresses list: M-x edb-format-addresses Go to middle of buffer C-u 5 M-< Set mark on the beginning of the first line of a nearby address, go to the end of the buffer, and kill the region: C-SPC M-> M-w Go to beginning of buffer: M-< Start two-column mode: M-x two-column RET Put the cursor into right hand window, go to beginning of that window, and yank the latter half of buffer into the right hand window: M-< C-y Merge the two columns: C-x 6 1 Insert a form feed every 63 lines M-x edb-sixty-three Or else, use a macro like this to do the same job: M-< C-x ( C-u 63 C-n C-q C-l RET C-x ) C-u C-u C-x e Save the file and print it using `lpr'. ================================================================ How to change the internal layout of a database file ==================================================== EDB can work with database data files in various internal layouts. As a user, you do not see these internal layouts, unless you choose to visit the file using `find-file' rather than `db-find-file'. You can convert from one layout to another. * Internal layout. EDB works best when a database data file is stored in an an internal layout, in Lisp, that is more efficient than any of the other forms. * Regular or Tab-delimited layouts. Tab-delimited database files are common through out the industry. This is the layout used to transfer and convert a database from one type of database software to another. I used this layout to transfer the sample database from the old Forms mode to EDB. You can use it to transfer databases to and from proprietary databases. * Non-regular layouts. EDB can use non-regular layouts. For example, EDB can treat a password file, as-is, as a database. You can create layouts that make it easy to read files without using the database. How to convert from a regular, tab-separated database layout to EDB's internal database layout ================================= Read in database. Set the `db-use-internal-rep-p' to `t' by typing: M-x set-variable RET db-use-internal-rep-p RET t RET and then write the database to a new file name by typing C-x C-w new-filename RET How to convert from EDB's internal database layout to a regular, tab-separated database layout =========================================== Read in database. Set the `db-use-internal-rep-p' to `nil' by typing: M-x set-variable RET db-use-internal-rep-p RET nil RET and then write the database to a new file name by typing C-x C-w new-filename RET How to add new fields to database. ================================= EDB has a built-in method to add new fields to an existing database, I cannot figure it out. The technique still lacks a friendly user interface. See the `db-convert.el' file. [Due to these limitations, and because no one seems to mind, db-convert.el was removed from EDB starting with release 1.27 and later. --ttn 2006-06-05] Instead, I do the following: First, convert the database from EDB's internal database layout to a regular, tab-separated database layout. In the tab-separated database layout, you can add new fields by adding new tabs in the right places in each record. For example, the original addresses data file lacked two fields, one listing the date of the last order and the other listing the type of order. You can write an elisp function such as the following that adds tabs to each record in the data file. Here is a function that searches for tabs in each record. It counts the number of tabs it finds and inserts new tabs after skipping past the appropriate number of exisiting tabs. ;; This adds two fields to each addresses list record after the tenth ;; tab in that record. (defun add-fields () "Add two fields to database." (interactive) (while (not (eobp)) (search-forward "\t" nil nil 10) ; search for ten tabs (insert "\t\t") ; insert additional tabs just after tenth tab (forward-line 1) )) The addresses format file is illustrated below. (See further below for the actual `addresses.fmt' file.) The addresses format file does not contain tabs (only the data file does), but the numbers shown below mark the location of each tab in the corresponding data file record. The `add-fields' function added the two tabs after tab number `10' to create the date and type fields. (Remember, this illustration is based on a format, `.fmt', file. You add tabs to the data, `.dat', file. After adding tabs to the data file, you need to revise the .fmt file to handle the new fields.) Name..............: \name,width=24 1 Mail Stop: \mail-stop 2 Dept..............: \dept 3 Company Name......: \company-name 4 Address line 1....: \address-line-1 5 Address line 2....: \address-line-2 6 City..............: \city,width=24 7 State: \state,width=6 8 Zip code: \zip 9 Telephone.........: \telephone 10 Date of last order: \order-date 11 Type (Company, Individual, etc.): \type 12 Remarks.......: \remarks The two new tabs were inserted before the Remarks field that already existed in the database. Here is the `sample.dat' file; this contains only one record: ;; Database file written by EDB; format 0.3 [database "Unnamed Database 4" nil 1 "/u/edb/sample.dat" nil nil nil nil nil 13 [name mail-stop dept company-name address-line-1 address-line-2 city state zip telephone order-date type remarks] ((name . 0) (mail-stop . 1) (dept . 2) (company-name . 3) (address-line-1 . 4) (address-line-2 . 5) (city . 6) (state . 7) (zip . 8) (telephone . 9) (order-date . 10) (type . 11) (remarks . 12)) [string string string string string string string string string string string string string] (((0) (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12))) nil [sepinfo nil nil nil " " nil nil nil nil nil nil] [sepinfo nil nil nil " " nil nil nil nil nil nil] [sepinfo nil nil nil nil nil nil nil nil nil nil] nil nil " " " " nil nil nil nil nil nil nil nil] ( ["John Doe " "MS Q007 " "Record keeping" "Alpha-Omega Inc" "Riverside Road" "P.O. Box 27" "Anytown " "MA" "01234" "(617) 234-5678" "10 March 1993" "Company" "Traditional Yankee personality."] ) Here is the `addresses.fmt' file: ====== U.S. Address list ====== Name..............: \name,width=24 Mail Stop: \mail-stop,width=10 Dept..............: \dept Company Name......: \company-name Address line 1....: \address-line-1 Address line 2....: \address-line-2 City..............: \city,width=24 State: \state,width=2 Zip code: \zip Telephone.........: \telephone Date of last order: \order-date Type (Company, Individual, etc.): \type ====== Remarks ====== Remarks.......: \remarks Local Variables: eval: (database-set-fieldnames-to-list database '(name mail-stop dept company-name address-line-1 address-line-2 city state zip telephone order-date type remarks)) eval: (dbf-set-summary-format "\\company-name,width=24 \\dept,width=12 \\name,width=12 \\city, \\state") End: Here is the `addresses.lbl' file: \name,width=24\mail-stop,width=10 \dept \company-name \address-line-1 \address-line-2 \city, \state,width=2 \zip Here is the `edb-format-addresses.el' file: ;;;;;;;;;;;;;;;; edb-format-addresses.el ;;;;;;;;;;;;;;;; ;; R. J Chassell ;; Make a list of addresses look neater. ;; Version 0.02 ;; 3 March 1993 ;; Improve documentation string. Tells how to use `edb-format-addresses'. ;; Version 0.01 ;; 20 July 1992 ; The function has two important features: ; ; * every address starts N lines down, so you can use it for printing ; sticky address labels; ; ; * blank lines are moved from the interior of the address to the end, ; so each printed address looks better. (defvar edb-printed-addresses-lines-per-record 7 "*Number of lines in address list as originally produced by EDB.") (defvar edb-printed-addresses-extra-lines 0 "*Number of additional blank lines printed in address list produced by EDB.") (defun edb-format-addresses () "Format addresses more neatly for printing. Visit buffer containing addresses list. Then type `M-x edb-format-addresses'. This command changes the buffer. Save the buffer. This command removes the blank lines within the body of each address and reinserts them at the end of the address. Each printed address continues to be the same number of lines long, but the blank lines are always at the end of the address field. The command should work with any EDB *Database Report* buffer formatted with six lines of potential text followed by one intentionally blank line; however it has only been tested with an EDB *Database Report* buffer formatted as follows \(the numbers not part of the record; the last line is blank\): 1 Customer Name mail stop code 2 Department name 3 Company name 4 First address line 5 Second address line 6 City, State Zip code 7 Any of the lines and fields in an address may be blank. The variable `edb-printed-addresses-lines-per-record' specifies the number of lines \(including the blank line at the end\) in the address as produced by EDB in the *Database Report* buffer. The default value is 7, and fits the format shown above. The variable `edb-printed-addresses-extra-lines' adds extra blank lines after the end of an address. The default value is 0. You may need extra blank lines to get each address to fit on address labels." (interactive) (widen) ; Just to be safe. (goto-char (point-min)) (let* ((lines-per-record edb-printed-addresses-lines-per-record) (line-number 1) (deleted-lines 0)) (while (not (eobp)) (if (looking-at "^$\\|^[ \t\n]*$") (progn (delete-region (1- (point)) (save-excursion (end-of-line) (point))) (setq deleted-lines (1+ deleted-lines)))) (forward-line 1) (setq line-number (1+ line-number)) ;; If this is the last line of the record, ;; insert requisit number of deleted lines. (if (zerop (% line-number lines-per-record)) (progn (insert-char ?\n deleted-lines) (setq deleted-lines 0) (insert-char ?\n edb-printed-addresses-extra-lines) (forward-line 1) (setq line-number (1+ line-number))))))) ;;; A seven or nine line label needs to be printed with 63 lines on ;;; each page. This does the job: (defun edb-sixty-three () "Insert Control-L every 63 lines." (interactive) (goto-char (point-min)) (while (not (eobp)) (next-line 63) (insert ?\C-l) (insert ?\n))) ;;;;;;;;;;;;;;;; end edb-format-addresses.el ;;;;;;;;;;;;;;;; ================ end how-to-use-EDB ================ edb-1.31/examples/names.dat0000644000175000017500000000002210745370011013767 0ustar ttnttnHarry S Truman 88 edb-1.31/examples/names.edb0000444000175000017500000000170610745370011013761 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :fields [first middle last (age . integer)] :display t Family: \last Given: \first Middle: \middle Age: \age :EOTB ;;; names.edb ends here edb-1.31/examples/names.fmt0000444000175000017500000000035110745370011014010 0ustar ttnttnFamily: \last Given: \first Middle: \middle Age: \age Local Variables: edb-data-coding: iso-safe eval: (database-set-fieldnames-to-list database '(first middle last (age . integer))) End: edb-1.31/examples/null.edb0000444000175000017500000000171610745370011013631 0ustar ttnttn;;; null.edb -*-emacs-lisp-*- ;; Copyright (C) 2007,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :EDB (single) :name "The NULL Device" :fields [dummy] :display t ===== Visiting /dev/null ===== "dummy" field value: \dummy :EOTB ;;; null.edb ends here edb-1.31/examples/passwd.edb0000444000175000017500000000227210745370011014156 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "Password database" :field-separator ":" :fields [username password (uid . integer) (gid . integer) gcos-field home-dir login-shell] :display t ====== Visiting /etc/passwd ====== User : \username,width=20 Uid: \uid,width=5 Gid: \gid Name : \gcos-field Home : \home-dir Shell: \login-shell :EOTB ;;; passwd.edb ends here edb-1.31/examples/passwd.fmt0000444000175000017500000000067710745370011014221 0ustar ttnttn====== Visiting /etc/passwd ====== User : \username,width=20 Uid: \uid,width=5 Gid: \gid Name : \gcos-field Home : \home-dir Shell: \login-shell Local Variables: eval: (let ((db database)) (database-set-fieldnames-to-list db '(username password uid gid gcos-field home-dir login-shell)) (setf (database-print-name db) "Password database" (sepinfo-sep-string (database-field-sepinfo db)) ":")) End: edb-1.31/examples/rolo-jik.dat0000644000175000017500000000070110745370011014416 0ustar ttnttnJonathan I. Kamens 617-374-3713 617-738-7684 Geer Zolot Associates This record contains no extra fields. Mon Mar 29 00:02:07 1993 Michael Ernst (206) 936-2272 Microsoft 1 Microsoft Way; Redmond, WA 98052 This record contains extra fields,; one of whose labels is wide. Mon Mar 29 00:01:08 1993 Birthday: March 14 Anniversary: None, so send lots of extra birthday presents Email: mernst@theory.lcs.mit.edu Alternate email: mernst@microsoft.com edb-1.31/examples/rolo-jik.dba0000444000175000017500000001351110745370011014375 0ustar ttnttn(setq rolodex-extras '("extra1" "extra2" "extra3" "extra4" "extra5")) (setq rolodex-fields '(name work-phone home-phone company work-address home-address remarks date (birthday . string-or-nil) (anniversary . string-or-nil))) (let ((extras rolodex-extras)) (while extras (setq rolodex-fields (append rolodex-fields (list (cons (intern (concat (car extras) "-name")) 'string-or-nil) (cons (intern (concat (car extras) "-value")) 'string-or-nil)))) (setq extras (cdr extras)))) (database-set-fieldnames-to-list database rolodex-fields) (setf (database-print-name database) "Jik's Rolodex" (sepinfo-sep-function (database-record-sepinfo database)) 'rolodex-sep-function) (defun rolodex-sep-function (last-end) (let (this-end) (if last-end (goto-char (+ last-end 1))) (if (re-search-forward ".*\n.*\n.*\n.*\n.*\n.*\n.*\n.*\n\\(.+\n\\)*" nil t) (setq this-end (match-end 0)) (error "Error separating rolodex record.")) (cons this-end (if (>= (+ this-end 1) (point-max)) nil (+ this-end 1))))) (setf (database-read-record-from-region database) 'rolodex-rrfr) (defun newlines->semis (string) (and string (replace-regexp-in-string "\n" "; " string))) (defun semis->newlines (string) (and string (replace-regexp-in-string ";[ \t]*" "\n" string))) (defun rolodex-rrfr () (unless (re-search-forward "\\(.*\\)\n\\(.*\\)\n\\(.*\\)\n\\(.*\\)\n\\(.*\\)\n\\(.*\\) \\(.*\\)\n\\(.*\\)\n" nil t) (error "Error parsing rolodex record.")) (let ((extras rolodex-extras) (name (match-string 1)) (work-phone (match-string 2)) (home-phone (match-string 3)) (company (match-string 4)) (work-address (match-string 5)) (home-address (match-string 6)) (remarks (match-string 7)) (date (match-string 8))) (nconc (list 'name (semis->newlines name) 'work-phone (semis->newlines work-phone) 'home-phone (semis->newlines home-phone) 'company (semis->newlines company) 'work-address (semis->newlines work-address) 'home-address (semis->newlines home-address) 'remarks (semis->newlines remarks) 'date (semis->newlines date)) (let (pl) (flet ((plpush (f v) (setq pl (plist-put pl f (semis->newlines v))))) (while (and extras (re-search-forward "\\(.+\\)\n" nil t)) (let ((extra (match-string 1))) (cond ((string-match "^Birthday:[ \t]*\\(.*\\)" extra) (plpush 'birthday (match-string 1 extra))) ((string-match "^Anniversary:[ \t]*\\(.*\\)" extra) (plpush 'anniversary (match-string 1 extra))) ((string-match "^\\([^:]+\\):[ \t]*\\(.*\\)" extra) (let ((field-name (match-string 1 extra)) (field-value (match-string 2 extra))) (plpush (intern (concat (car extras) "-name")) field-name) (plpush (intern (concat (car extras) "-value")) field-value) (setq extras (cdr extras)))) (t (error "Invalid extra field parsing rolodex record.")))))) pl)))) (setf (database-write-region-from-record database) 'rolodex-wrfr) (defun empty-string-or-nil-p (string-or-nil) "Return t if its argument is nil or a zero-length string, nil otherwise." (or (not string-or-nil) (string-equal "" string-or-nil))) (defun rolodex-wrfr (record) (insert (newlines->semis (db-record-field record 'name)) "\n" (newlines->semis (db-record-field record 'work-phone)) "\n" (newlines->semis (db-record-field record 'home-phone)) "\n" (newlines->semis (db-record-field record 'company)) "\n" (newlines->semis (db-record-field record 'work-address)) "\n" (newlines->semis (db-record-field record 'home-address)) "\n" (newlines->semis (db-record-field record 'remarks)) "\n" (newlines->semis (db-record-field record 'date)) "\n") (let ((extras rolodex-extras) (birthday (db-record-field record 'birthday)) (anniversary (db-record-field record 'anniversary))) (if (not (empty-string-or-nil-p birthday)) (insert "Birthday: " (newlines->semis birthday) "\n")) (if (not (empty-string-or-nil-p anniversary)) (insert "Anniversary: " (newlines->semis anniversary) "\n")) (while extras (let ((extra-name (db-record-field record (intern (concat (car extras) "-name")))) (extra-value (db-record-field record (intern (concat (car extras) "-value"))))) (if (not (and (empty-string-or-nil-p extra-name) (empty-string-or-nil-p extra-value))) (insert extra-name ": " (newlines->semis extra-value) "\n"))) (setq extras (cdr extras))))) (defun rolodex-before-display (&optional record) (let ((width rolodex-min-field-width) (extras rolodex-extras)) (while extras (let ((name (db-record-field (or record t) (intern (concat (car extras) "-name"))))) (if (and (not (empty-string-or-nil-p name)) (> (length name) width)) (setq width (length name)))) (setq extras (cdr extras))) (setq tab-width (+ width 2)))) (setq dbf-before-display-record-function 'rolodex-before-display) ; I could cache some state in the record so that I only have to ; redisplay it if the tab width actually changes, or only if the field ; being changed is one of the extra fields' names, but it isn't worth ; the effort. (defun rolodex-change-function (field old new) (rolodex-before-display) t) (setq dbf-every-change-function 'rolodex-change-function) (defun rolodex-change-date (field old new) (dbf-this-record-set-field 'date (current-time-string))) (setq dbf-first-change-function 'rolodex-change-date) edb-1.31/examples/rolo-jik.doc0000444000175000017500000000254410745370011014420 0ustar ttnttnDate: Mon, 22 Mar 93 12:21:52 -0500 From: "Jonathan I. Kamens" The format of the rolodex used by the "rolo" program is as follows: The first eight lines of each entry in the rolodex contain the name, work phone, home phone, company, work address, home address, remarks and modification date of the entry. The field name for each of those lines is not included, because they are always the same fields in the same order. Then, subsequent lines contain extra fields (I'm not sure how many extra fields the program actually allows; my EDB database allows five), in the format "Name: value". The entry is terminated by a blank line. Semicolons in field values are displayed by rolo as newlines, so they are displayed by my EDB database as newlines as well. In addition, since I consider the "Birthday" and "Anniversary" fields to be very important, I've displayed them as main fields in my database, even though they're extra fields in the rolo program. One of the things I like most about my database is that it automatically sets the tab width so that all of the field values are lined up, even when a long extra field name is created. Note, however, that this is limited by the fact that emacs 18.59 has a maximum tab width (for some unknown reason) of 20. I've posted to gnu.emacs.bug, complaining about this and sending a patch to remove the restriction. edb-1.31/examples/rolo-jik.edb0000444000175000017500000001564010745370011014406 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "Jik's Rolodex" (setq rolodex-extras '("extra1" "extra2" "extra3" "extra4" "extra5") rolodex-extras-fields (apply 'append (mapcar (lambda (x) (list (intern (concat x "-name")) (intern (concat x "-value")))) rolodex-extras))) :fields `[name work-phone home-phone company work-address home-address remarks date (birthday . string-or-nil) (anniversary . string-or-nil) ,@(mapcar (lambda (name) (cons name 'string-or-nil)) rolodex-extras-fields)] :record-separator-function (defun rolodex-sep-function (last-end) (let (this-end) (if last-end (goto-char (+ last-end 1))) (if (re-search-forward ".*\n.*\n.*\n.*\n.*\n.*\n.*\n.*\n\\(.+\n\\)*" nil t) (setq this-end (match-end 0)) (error "Error separating rolodex record.")) (cons this-end (if (>= (+ this-end 1) (point-max)) nil (+ this-end 1))))) (defun newlines->semis (string) (and string (replace-regexp-in-string "\n" "; " string))) (defun semis->newlines (string) (and string (replace-regexp-in-string ";[ \t]*" "\n" string))) (defvar rolo-jik-regexp (concat "\\(.*\\)\n\\(.*\\)\n\\(.*\\)\n\\(.*\\)\n\\(.*\\)\n\\(.*\\)\n" "\\(.*\\)\n\\(.*\\)\n") "Regular expression used by `rolodex-read-record'.") :read-record (defun rolodex-read-record () (unless (re-search-forward rolo-jik-regexp nil t) (error "Error parsing rolodex record.")) (let ((extras rolodex-extras) (name (match-string 1)) (work-phone (match-string 2)) (home-phone (match-string 3)) (company (match-string 4)) (work-address (match-string 5)) (home-address (match-string 6)) (remarks (match-string 7)) (date (match-string 8))) (nconc (list 'name (semis->newlines name) 'work-phone (semis->newlines work-phone) 'home-phone (semis->newlines home-phone) 'company (semis->newlines company) 'work-address (semis->newlines work-address) 'home-address (semis->newlines home-address) 'remarks (semis->newlines remarks) 'date (semis->newlines date)) (let (pl) (flet ((plpush (f v) (setq pl (plist-put pl f (semis->newlines v))))) (while (and extras (re-search-forward "\\(.+\\)\n" nil t)) (let ((extra (match-string 1))) (cond ((string-match "^Birthday:[ \t]*\\(.*\\)" extra) (plpush 'birthday (match-string 1 extra))) ((string-match "^Anniversary:[ \t]*\\(.*\\)" extra) (plpush 'anniversary (match-string 1 extra))) ((string-match "^\\([^:]+\\):[ \t]*\\(.*\\)" extra) (let ((field-name (match-string 1 extra)) (field-value (match-string 2 extra))) (plpush (intern (concat (car extras) "-name")) field-name) (plpush (intern (concat (car extras) "-value")) field-value) (setq extras (cdr extras)))) (t (error "Invalid extra field parsing rolodex record.")))))) pl)))) (defun empty-string-or-nil-p (string-or-nil) "Return t if its argument is nil or a zero-length string, nil otherwise." (or (not string-or-nil) (string-equal "" string-or-nil))) :write-record (defun rolodex-write-record () (insert (newlines->semis name) "\n" (newlines->semis work-phone) "\n" (newlines->semis home-phone) "\n" (newlines->semis company) "\n" (newlines->semis work-address) "\n" (newlines->semis home-address) "\n" (newlines->semis remarks) "\n" (newlines->semis date) "\n") (unless (empty-string-or-nil-p birthday) (insert "Birthday: " (newlines->semis birthday) "\n")) (unless (empty-string-or-nil-p anniversary) (insert "Anniversary: " (newlines->semis anniversary) "\n")) (let ((extras rolodex-extras-fields)) (while extras (let ((name (eval (car extras))) (value (eval (cadr extras)))) (unless (or (empty-string-or-nil-p name) (empty-string-or-nil-p value)) (insert name ": " (newlines->semis value) "\n"))) (setq extras (cddr extras))))) (setq rolodex-min-field-width 13) :before-display (defun rolodex-before-display (extra1-name extra2-name extra3-name extra4-name extra5-name) (setq tab-width (+ 2 (apply 'max rolodex-min-field-width (mapcar 'length (list extra1-name extra2-name extra3-name extra4-name extra5-name)))))) :every-change-function ;; I could cache some state in the record so that I only have to ;; redisplay it if the tab width actually changes but it isn't worth ;; the effort. (defun rolodex-change-function (field old new) (when (memq field '(extra1-name extra2-name extra3-name extra4-name extra5-name)) (setq tab-width (max rolodex-min-field-width (length new)))) t) :first-change-function (defun rolodex-change-date (field old new) (dbf-this-record-set-field 'date (current-time-string))) :display t Name: \name Work phone: \work-phone Home phone: \home-phone Company: \company Work address: \work-address Home address: \home-address Remarks: \remarks Birthday: \birthday Anniversary: \anniversary \extra1-name: \extra1-value \extra2-name: \extra2-value \extra3-name: \extra3-value \extra4-name: \extra4-value \extra5-name: \extra5-value Last modified: \date,unreachable :EOTB ;;; rolo-jik.edb ends here edb-1.31/examples/rolo-jik.fmt0000444000175000017500000000065010745370011014435 0ustar ttnttnName: \name Work phone: \work-phone Home phone: \home-phone Company: \company Work address: \work-address Home address: \home-address Remarks: \remarks Birthday: \birthday Anniversary: \anniversary \extra1-name: \extra1-value \extra2-name: \extra2-value \extra3-name: \extra3-value \extra4-name: \extra4-value \extra5-name: \extra5-value Last modified: \date,unreachable Local Variables: rolodex-min-field-width: 13 End: edb-1.31/examples/tepdb0000644000175000017500000000456310745370011013231 0ustar ttnttn;; Database file written by EDB; format 0.7 ["TEP Alumni database" [last-name first-name jr class-year initiation-date nickname home-address home-city home-state home-zip home-phone biz-title biz-company-name biz-address biz-city biz-state biz-zip biz-phone address-preferred hold-address-from degrees degree-courses degree-dates birthdate computer-address married death-date type big-brother old-home-address old-home-city old-home-state old-home-zip old-home-phone old-biz-title old-biz-company-name old-biz-name/title old-biz-address old-biz-city old-biz-state old-biz-zip old-biz-phone parents-name parents-address parents-city parents-state parents-zip parents-phone contact-date question-mark comments] [string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string string] nil [nil nil nil "\n" "\n" 0 nil nil nil nil] [nil nil nil "\n" "\n" 0 nil nil nil nil] nil nil "" "" (("\n" . " ")) nil] ((:format-file . "tepdb.fmt")) ["Abrams" "Robert A." "" "1961" "" "" "454 Jackson" "Glencoe" "IL" "60022" "312-835-1992" "" "University of IL Chicago" "College of Bus Admin" "Chicago" "IL" "60680" "312-996-2676" "" "" "SB" "8" "" "" "" "" "" "brother" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "Nov 10 90" "" ""] ["Allen" "Ernest" "3rd" "1974" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "3 SB's" "18,8,21B" "" "" "" "" "" "brother" "" "311 S Branciforte" "Santa Cruz" "CA" "95062" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "Feb 2 88" "" ""] ["Alter" "Ralph" "" "1959" "" "" "121 Worchester Ln" "Waltham" "MA" "02154" "617-899-4225" "" "Interleaf Inc" "Ten Canal Park" "Cambridge" "MA" "02141" "617-577-9800" "" "" "SB SM SCD" "6A" "" "" "" "" "" "brother" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "Feb 2 88" "" ""] ["Alter" "Steven L." "" "1967" "" "" "2736 Fulton Avenue" "San Francisco" "CA" "94118" "415-752-7837" "" "Professor of Info Sys & Mangmnt" "U of SF college of business" "Ignatian Hgts, San Francisco" "CA" "94117" "415-666-6383" "" "" "SB, PhD" "18, 15" "" "" "" "" "" "brother" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "Feb 2 88" "" ""] edb-1.31/examples/tepdb.dba0000444000175000017500000003115310745370011013747 0ustar ttnttn;;; -*-Emacs-Lisp-*- ;;; To do: ;; The interactive functions should check that they're in the right buffer ;; (namely, database buffer) before executing. ;; Should omit deceased brothers from some reports. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Noninteractive functions ;;; ;;; These combine several fields to give a single result. ;; This should truncate middle names to a single letter, if there's a full ;; first name there. (defun tep-record-fullname (record) (concat (db-record-field record 'first-name) " " (db-record-field record 'last-name) (let ((jr (db-record-field record 'jr))) (if (empty-string-p jr) "" (concat ", " jr))))) (defun tep-record-biz-address (record) (let ((title (db-record-field record 'biz-title)) (company-name (db-record-field record 'biz-company-name)) (address (db-record-field record 'biz-address))) (if (not (empty-string-p address)) (concat (if (empty-string-p title) "" (concat title "\n")) (if (empty-string-p company-name) "" (concat company-name "\n")) address "\n" (db-record-field record 'biz-city) ", " (db-record-field record 'biz-state) " " (db-record-field record 'biz-zip))))) (defun tep-record-home-address (record) (let ((address (db-record-field record 'home-address))) (if (not (empty-string-p address)) (concat address "\n" (db-record-field record 'home-city) ", " (db-record-field record 'home-state) " " (db-record-field record 'home-zip))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Change hooks ;;; ;; These should display a message admitting what they've just done. ;; (Not if they ask the user first, perhaps.) ;; Change hooks return t if the record should be redisplayed. (defun tepdb:after-read () (setq dbf-first-change-function 'tep-contact-date) ;; transitional (EDB 1.x to 2.x) approach; likely to change --ttn (set (make-local-variable 'db-edit-mode-hooks) (lambda () (dolist (var '(tep-homeaddr-oldified tep-homephone-oldified tep-bizaddr-oldified tep-bizphone-oldified)) (set (make-local-variable var) nil)))) (dbf-set-change-function 'home-address 'tep-homeaddr-change-hook) (dbf-set-change-function 'home-city 'tep-homeaddr-change-hook) (dbf-set-change-function 'home-state 'tep-homeaddr-change-hook) (dbf-set-change-function 'home-zip 'tep-homeaddr-change-hook) (dbf-set-change-function 'home-phone 'tep-homephone-change-hook) (dbf-set-change-function 'biz-address 'tep-bizaddr-change-hook) (dbf-set-change-function 'biz-city 'tep-bizaddr-change-hook) (dbf-set-change-function 'biz-state 'tep-bizaddr-change-hook) (dbf-set-change-function 'biz-zip 'tep-bizaddr-change-hook) (dbf-set-change-function 'biz-phone 'tep-bizphone-change-hook) (remove-hook 'db-after-read-hooks 'tepdb:after-read)) (add-hook 'db-after-read-hooks 'tepdb:after-read) ;;; ;;; Defeat the change hooks ;;; ;; This is moot now that the user is always queried before changes are made ;; anyway. (defun tep-fix-typo () (interactive) "Prevent contact-date, old address fields from changing when record is edited." (if (not (db-format-buffer-p)) (error "Only call tep-fix-typo in a database format buffer.")) (setq tep-homeaddr-oldified t) (setq tep-homephone-oldified t) (setq tep-bizaddr-oldified t) (setq tep-bizphone-oldified t) ;; defeat first-change-function, at a small price if the record isn't changed (dbf-set-this-record-modified-p t)) ;;; ;;; Contact date ;;; (defun tep-contact-date (fieldname oldvalue newvalue) "Put the current date in this record's `contact date' field." (dbf-this-record-set-field 'contact-date (let ((now (current-time-string))) (concat (substring now 4 8) (substring now 8 11) (substring now 20))))) ;; Add "defeat" mechanisms for phone as well. ;;; ;;; Home address ;;; ;; All the obnoxious questions are asked because it's too easy to ;; accidentally knock out the old home address when making a minor edit. (defvar tep-homeaddr-oldified nil) (defvar tep-homephone-oldified nil) (defun tep-homeaddr-change-hook (fieldname oldvalue newvalue) (if (and (not tep-homeaddr-oldified) (y-or-n-p "Move previous home address to old home address fields? ")) (progn (dbf-this-record-set-field 'old-home-address (if (eq fieldname 'home-address) oldvalue (db-record-field t 'home-address))) (dbf-this-record-set-field 'old-home-city (if (eq fieldname 'home-city) oldvalue (db-record-field t 'home-city))) (dbf-this-record-set-field 'old-home-state (if (eq fieldname 'home-state) oldvalue (db-record-field t 'home-state))) (dbf-this-record-set-field 'old-home-zip (if (eq fieldname 'home-record) oldvalue (db-record-field t 'home-zip))) (setq tep-homeaddr-oldified t) t) (progn (setq tep-homeaddr-oldified t) nil))) (defun tep-homephone-change-hook (fieldname oldvalue newvalue) (if (and (not tep-homephone-oldified) (y-or-n-p "Move previous home phone to old-home-phone field? ")) (progn (dbf-this-record-set-field 'old-home-phone oldvalue) (setq tep-homephone-oldified t) t) (progn (setq tep-homephone-oldified t) nil))) ;;; ;;; Business address ;;; (defvar tep-bizaddr-oldified nil) (defvar tep-bizphone-oldified nil) (defun tep-bizaddr-change-hook (fieldname oldvalue newvalue) (if (and (not tep-bizaddr-oldified) (y-or-n-p "Move previous business address to old business address fields? ")) (progn (dbf-this-record-set-field 'old-biz-address (if (eq fieldname 'biz-address) oldvalue (db-record-field t 'biz-address))) (dbf-this-record-set-field 'old-biz-city (if (eq fieldname 'biz-city) oldvalue (db-record-field t 'biz-city))) (dbf-this-record-set-field 'old-biz-state (if (eq fieldname 'biz-state) oldvalue (db-record-field t 'biz-state))) (dbf-this-record-set-field 'old-biz-zip (if (eq fieldname 'biz-record) oldvalue (db-record-field t 'biz-zip))) (setq tep-bizaddr-oldified t) t) (progn (setq tep-bizaddr-oldified t) nil))) (defun tep-bizphone-change-hook (fieldname oldvalue newvalue) (if (and (not tep-bizphone-oldified) (y-or-n-p "Move previous business phone to old-home-phone field? ")) (progn (dbf-this-record-set-field 'old-biz-phone oldvalue) (setq tep-bizphone-oldified t) t) (progn (setq tep-bizphone-oldified t) nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Reports (except labels) ;;; (defun tep-report-directory () (let ((sysname (system-name))) (cond ((member sysname '("emu" "coot" "swallow")) (expand-file-name "~mernst/tep/db/report/")) (t ;; Assume we're on athena ;; "/mit/tep/Alumni/Database/Report/" ;; Actually, we are far past the decstation dayz... "/tmp/")))) ;;; ;;; All four reports ;;; (defun tep-all-reports () (interactive) (tep-year-report) (tep-firstname-report) (tep-nickname-report) ;; This is last so the database is left in a reasonable sorted order. (tep-address-report) (message "Wrote four *-report.out files.") ) ;;; ;;; Abstraction ;;; (defun tep-report (filename sort-fieldnames fixup) (let ((base (expand-file-name filename (tep-report-directory)))) (save-excursion (database-sort nil (list (mapcar 'list sort-fieldnames))) (dbf-finished-sorting) (db-report base) ;; We're now in the *Database Report* buffer. (when fixup (funcall fixup)) (write-file (concat base ".out"))))) ;;; ;;; Address report ;;; (defun tep-address-report () (interactive) ;; I should include the contact date in this report. (tep-report "address-report" '(last-name first-name) ;; I realize this is a crock. Cut me some slack! I'll fix it later. ;; Make the address report in this buffer look nicer. (lambda () ;; Get rid of "Parents" (if address != "house") or "house" (goto-char (point-min)) (while (search-forward "house\n, \n\nPar" nil t) (replace-match "Squar" nil t)) (goto-char (point-min)) ;; Assumes one one line in parents' address. (replace-regexp "Parents:\\\n.*\\\n.*\\\n.*\\\n.*\\\nBus" "Bus") (goto-char (point-min)) (while (search-forward "Squaren" nil t) (replace-match "Paren" nil t)) (goto-char (point-min)) (while (search-forward "\n\n" nil t) (replace-match "\n")) (goto-char (point-min)) (while (search-forward "Business:\n, \n-" nil t) (replace-match "-")) (goto-char (point-min)) ;; Get rid of empty "Jr." parts of names. (while (search-forward ", \n" nil t) (replace-match "\n")) (goto-char (point-min)) (while (search-forward "\n \n" nil t) (replace-match "\n")) (goto-char (point-min)) (while (search-forward ", \n" nil t) (replace-match "\n")) (goto-char (point-min)) (while (search-forward "\n\n" nil t) (replace-match "\n")) (goto-char (point-min)) (while (search-forward "-----" nil t) (delete-region (match-beginning 0) (match-end 0))) (goto-char (point-min)) (while (search-forward "Business:\n\n" nil t) (delete-region (match-beginning 0) (match-end 0))) (goto-char (point-min)) (while (search-forward "\n\n\n" nil t) (replace-match "\n\n"))))) ;;; ;;; Year report ;;; (defun tep-year-report () (interactive) (tep-report "year-report" '(class-year last-name) (lambda () ;; Get rid of empty "Jr." parts of names. (while (search-forward ", \\\\\n" nil t) (replace-match " \\\\\n" nil t))))) ;;; ;;; Firstname report ;;; (defun tep-firstname-report () (interactive) ;; (I need to ignore the middle initial in this sorting.) (tep-report "firstname-report" '(first-name last-name) nil)) ;;; ;;; Nickname report ;;; (defun tep-nickname-report () (interactive) (tep-report "nickname-report" '(nickname) (lambda () ;; Get rid of empty "Jr." parts of names. (while (search-forward ", \\\\\n" nil t) (replace-match " \\\\\n" nil t)) ;; Get rid of lines with no nickname. (goto-char (point-min)) (delete-matching-lines "^ ")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Labels ;;; ;; Results go into the *TEP labels* buffer. ;; Save to a file (say, in the reports directory). ;; Run TeX (not LaTeX) on ~/tex/make-labels.tex to process the output. ;; Print make-labels.dvi. (defun tep-labels () (interactive) (db-maprecords (lambda (record) (let ((name (tep-record-fullname record)) (address (if (string-equal "B" (db-record-field record 'address-preferred)) (tep-record-biz-address record) (tep-record-home-address record)))) ;; (message "found name %s and address %s" name) (if address (princ (format "%s\n%s\n\n" name address) (get-buffer-create "*TEP labels*"))))))) ;; only marked records, I think (defun tep-labels/marked () (interactive) (db-maprecords (lambda (record) (let ((name (tep-record-fullname record)) (address (if (string-equal "B" (db-record-field record 'address-preferred)) (tep-record-biz-address record) (tep-record-home-address record)))) ;; (message "found name %s and address %s" name) (if address (princ (format "%s\n%s\n\n" name address) (get-buffer-create "*TEP labels*"))))) nil t) (switch-to-buffer-other-window "*TEP labels*")) (defun tep-local-labels () (interactive) ;; Go to state field. (db-first-field) (db-next-field 8) ;; Select local alumni: those with "MA" in the state. (C-u M-s ma RET) (db-search-field "MA" t) (db-omit-unmarked-records) (db-view-mode) ;; Sort on class year. (database-sort nil '(((3)))) ;; Create labels. (tep-labels)) ;; As of 3/23/92, the file make-labels.tex looked like this, without the ;; leading "; " on each line. ; \input labels ; \vlbls=11 \hlbls=3 ; \vfirst=0pt ; \hfirst=0pt ; \vinter=0pt ; \hinter=0pt ; \vlblsize=1in ; \hlblsize=2.833in ; % \vindent ; % \hindent ; ; % \lbloutline=0.5pt ; ; % \erroraction=1 ; ; \font\twelverm=cmr12 ; \twelverm ; ; \message{What is the label file? } ; \read-1 to\labeldatafile ; ; \labelfile{\labeldatafile} ; \bye edb-1.31/examples/tepdb.fmt0000444000175000017500000000230710745370011014006 0ustar ttnttnTEP Alumni Database \last-name, \first-name, \jr Nickname: \nickname Class year: \class-year Initiated: \initiation-date Address: \home-address \home-city, \home-state \home-zip Phone: \home-phone Business title: \biz-title Company name: \biz-company-name Address: \biz-address \biz-city, \biz-state \biz-zip Phone: \biz-phone Preferred address: \address-preferred Hold address from: \hold-address-from Degrees: \degrees Courses: \degree-courses Dates: \degree-dates Birthdate: \birthdate Computer address: \computer-address Married: \married Date of death: \death-date Type: \type Big brother: \big-brother Old home address: \old-home-address \old-home-city, \old-home-state \old-home-zip Phone: \old-home-phone Old Business title: \old-biz-title Company name: \old-biz-company-name Address: \old-biz-address \old-biz-city, \old-biz-state \old-biz-zip Phone: \old-biz-phone Parents: \parents-name Address: \parents-address \parents-city, \parents-state \parents-zip Phone: \parents-phone Contact date: \contact-date Question-mark: \question-mark Comments: \comments edb-1.31/examples/tepdb.instr0000444000175000017500000000764710745370011014373 0ustar ttnttnUsing the TEP Alumni Database ============================= This document describes the use of the TEP Alumni Database with EDB, an Emacs database package. It is presumed that you know how to use EDB; see its manual for instructions on doing database operations like moving from record to record, finding a particular record, editing fields of a record, sorting records, etc. * The address consists of several fields The address, city, state, and zip are separate fields. Don't try to just type the entire address all at once; use the TAB key to get to the next field. * Automatic updating of contact date and old address and phone fields Whenever a database record is edited, the "contact date" field is set to the current date. When any of the residence fields (home-address, home-city, home-state, or home-zip) are edited, the user is queried whether to set all four old residence fields are set to the previous values of the residence fields. So, for instance, if the home address is 253 Commonwealth Avenue Boston, MA 02115 and the old home address is 123 Boring Street Smallville, USA 00000 and we edit the home-zip field from 02115 to 02116, and answer "y" to the "Move previous home address to old-address fields?" question, then the new home address will be 253 Commonwealth Avenue Boston, MA 02116 and the old home address will become 253 Commonwealth Avenue Boston, MA 02115 The Smallville address has been lost. It should be obvious when to answer "y" and when to answer "n" to the question. Similar mechanisms are in place for the home phone number (which is separately managed because it and the address may change independently) and for the business address and phone number. Having fields automatically updated is is a good feature when the address is really changing, since it means you don't have to set the old address fields by hand. It is a nuisance when you are just fixing typos. In order to defeat these mechanisms, do M-x tep-fix-typo No fields will be automatically updated after you run this command. Alternately (and more simply), just answer "n" to the questions as they're asked. * Making reports You can use the commands M-x tep-address-report M-x tep-year-report M-x tep-firstname-report M-x tep-nickname-report to create files such as "address-report.out" in the /Alumni/Database/Reports directory. You can use these files directly, or typeset them by running the LaTeX program; from the command line, say latex address-report.tex to create the file address-report.dvi, which you can print by doing lpr -d address-report.dvi You can use M-x tep-all-reports to create all the .out files, but you'll still have to run LaTeX on them, and print them, one at a time. * Making labels Use M-x tep-labels to create mailing labels. This creates a buffer named *TEP labels* which contains the preferred mailing address of each alumnus. You'll want to save this buffer to a file. On athena, the filename should have an extension (contain a period in the name). To create a *TEP labels* buffer with only Massachusetts alumni, ordered by class year, do M-x tep-local-labels. If you have access to the "Midnight macros" for TeX, you can process this file by running TeX on the file make-labels.tex; from the Unix command line: tex make-labels and then printing the resulting file: lpr -d make-labels.dvi If you're on athena, then, you need to be using the SIPB TeX macros; do setenv TEXINPUTS .:/mit/sipb/lib/tex/macros in your .login. The file make-labels.tex can be found at the end of leber-db.dba if you don't have it already. (On athena, see the Reports directory.) If the top line on each page gets cut off by your printer, change the line in make-labels.tex that looks like \vfirst=0pt to \vfirst=5pt You can play with the parameter value to get it right; there are 72 pts in an inch. edb-1.31/examples/www-links0000644000175000017500000000026210745370011014065 0ustar ttnttnhttp://www.gnu.org/ http://www.gnu.org/software/ http://www.gnu.org/software/emacs/ http://www.gnuvola.org/ http://www.gnuvola.org/software/ http://www.gnuvola.org/software/edb/ edb-1.31/examples/www-links.edb0000444000175000017500000000165410745370011014622 0ustar ttnttn;;; www-links.edb -*-emacs-lisp-*- ;; Copyright (C) 2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :EDB (single) :name "WWW Links" :fields [url] :display t \url :EOTB ;;; www-links.edb ends here edb-1.31/examples/www-links20000644000175000017500000000035110745370011014146 0ustar ttnttnhttp://www.gnu.org/GNU http://www.gnu.org/software/GNU Software http://www.gnu.org/software/emacs/GNU Emacs http://www.gnuvola.org/GNUVOLA http://www.gnuvola.org/software/GNUVOLA SOFTWARE http://www.gnuvola.org/software/edb/EDBedb-1.31/examples/www-links2.edb0000444000175000017500000000174010745370011014700 0ustar ttnttn;;; www-links2.edb -*-emacs-lisp-*- ;; Copyright (C) 2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :EDB (single) :name "WWW Links (Titled)" :fields [url title] :field-separator "\C-t" :display t \title \url :EOTB ;;; www-links2.edb ends here edb-1.31/examples/www-links30000644000175000017500000000046410745370011014154 0ustar ttnttnhttp://www.gnu.org/GNUclassic, what can i say? some things should never change! http://www.gnu.org/software/GNU Software http://www.gnu.org/software/emacs/GNU Emacs http://www.gnuvola.org/GNUVOLA http://www.gnuvola.org/software/GNUVOLA SOFTWARE http://www.gnuvola.org/software/edb/EDB edb-1.31/examples/www-links3.edb0000444000175000017500000000242510745370011014702 0ustar ttnttn;;; www-links3.edb -*-emacs-lisp-*- ;; Copyright (C) 2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :EDB (single) :name "WWW Links (Everything)" (edb-define-recordfieldtype 'suredate 'date :actual->stored 'edb-t-timedate1:format-date-iso :stored->actual 'edb-t-timedate1:parse-date-string) :fields [url title (last-check . suredate) comments] :record-separator "\C-l" :field-separator "\C-t" :display t \title \url (\last-check,date-iso) Comments: \comments :EOTB :summary-format "\\last-check,width=11 \\title" ;;; www-links3.edb ends here edb-1.31/lisp/0000755000175000017500000000000011016452347011336 5ustar ttnttnedb-1.31/lisp/GNUmakefile.in0000444000175000017500000000551611005373425014017 0ustar ttnttn# GNUmakefile for EDB subdir "lisp". # Copyright (C) 2008 Thien-Thi Nguyen # # This file is part of EDB. # # EDB 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 3, or (at your option) any later # version. # # EDB 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 EDB; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. srcdir = @srcdir@ top_srcdir = @top_srcdir@ prefix = @prefix@ datarootdir = @datarootdir@ datadir = @datadir@ infodir = @infodir@ sitelisp = @sitelisp@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ mkinstalldirs = $(top_srcdir)/install-sh -d EDB-VERSION = @PACKAGE_VERSION@ edb-elc-dir = $(sitelisp)/edb EMACS = @EMACS@ EXTRABATCHOPTS = --no-site-file ebatch = $(EMACS) -batch $(EXTRABATCHOPTS) VPATH = $(srcdir) badnamesp = @badnamesp@ badnames-el = db-nosetf.el db-oldnames.el edbcore-lispfrags = system state connection edbcore-dbfrags = util rep format file-io interfa types summary edbcore-components = \ $(edbcore-lispfrags:%=%.el) \ $(edbcore-dbfrags:%=db-%.el) generated = edbcore.el dontcompile = db-lemacs.el db-nosetf.el db-oldnames.el typelibs-frags = human-names places-usuk timedate1 typelibs = $(typelibs-frags:%=edb-t-%.el) normal-lispfrags = 1int-to-single meta normal-frags = isbn rdb search sort tagged two-dbs normal = database.el \ $(normal-frags:%=db-%.el) \ $(normal-lispfrags:%=edb-%.el) source-el-files = $(edbcore-components) $(normal) $(typelibs) installed-el-files = $(generated) $(normal) $(typelibs) installed-elc-files = $(addsuffix c, $(installed-el-files)) all: $(installed-elc-files) $(installed-elc-files): $(source-el-files) $(ebatch) \ --eval '(setq vc-handled-backends nil)' \ --eval '(setq load-path (cons "$(srcdir)" load-path))' \ -l bfuncs \ -f edb-bfunc-make-all clean: $(RM) $(installed-elc-files) $(generated) # Install *.elc after *.el in case $(INSTALL_DATA) clobbers mtime. install: all $(mkinstalldirs) $(edb-elc-dir) $(RM) $(edb-elc-dir)/*.el $(edb-elc-dir)/*.elc $(INSTALL_DATA) $(installed-el-files) $(edb-elc-dir) $(INSTALL_DATA) $(installed-elc-files) $(edb-elc-dir) $(INSTALL_DATA) $(dontcompile) $(edb-elc-dir) $(badnamesp) || $(RM) $(addprefix $(edb-elc-dir)/, $(badnames-el)) installcheck: $(ebatch) --eval '(message "%s" load-path)' --kill 2>&1 \ | sed 's, ,:,g;s,(,,;s,),,' > TMP EMACSLOADPATH=$(sitelisp):`cat TMP` \ $(ebatch) --load database --kill $(RM) TMP # GNUmakefile ends here edb-1.31/lisp/bfuncs0000444000175000017500000001132211005375020012524 0ustar ttnttn;;; bfuncs --- some -*-emacs-lisp-*- for "emacs -batch" invocation ;;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; This file, deliberately named w/o .el suffix, is not installed. ;; It contains various thunks for invocation from the GNUmakefile. ;;; Code: (unless noninteractive (error "File not intended for interactive use -- see GNUmakefile")) (require 'cl) (require 'pp) (defun edb-bfunc-get-GNUmakefile (var) (interactive "sVar: ") (let ((ans (with-temp-buffer (insert "zup:\n\t@echo \"$(" var ")\"\n") (call-process-region (point-min) (point-max) "make" t t nil "--no-print-directory" "-f" "GNUmakefile" "-f" "-" "zup") (buffer-substring (point-min) (1- (point-max)))))) (if (interactive-p) (message "%s" ans) (split-string ans)))) (defun edb-bfunc-make-edbcore () (let ((writep (not (file-exists-p "edbcore.el"))) (badnamesp (equal '("true") (edb-bfunc-get-GNUmakefile "badnamesp"))) (ls (edb-bfunc-get-GNUmakefile "edbcore-components"))) (unless writep (dolist (file ls) (setq writep (or writep (file-newer-than-file-p file "edbcore.el"))))) (when writep (with-temp-buffer (dolist (file ls) (insert-file-contents file) (goto-char (point-max))) (insert "\n(provide 'edbcore)") (let (b e acc) (goto-char (point-min)) (while (re-search-forward "^(:edb1 .*)\n\n" (point-max) t) (setq b (match-beginning 0) e (match-end 0) acc (cons (buffer-substring b e) acc)) (delete-region b e)) (search-backward ":further-init edb--global-state") (delete-region (point) (progn (forward-line 1) (point))) (let ((standard-output (current-buffer))) (pp '(edb--rput nil :edb1 (make-hash-table :size 7 :test 'eq))) (dolist (text (nreverse acc)) (let ((form (car (read-from-string text)))) (pp `(unless (edb--rget '(:edb1) ,(cadr form)) (edb--rput '(:edb1) ,(cadr form) ,(caddr form)))))))) (let ((rx (concat "\n;;;###badname" (unless badnamesp "\n.*")))) (goto-char (point-min)) (while (re-search-forward rx (point-max) t) (delete-region (match-beginning 0) (match-end 0)))) (let (decl) (goto-char (point-min)) (while (re-search-forward ";;;###safe-file-local-variable" (point-max) t) (save-excursion (down-list 1) (forward-sexp 1) (setq decl `(put ',(read (current-buffer)) 'safe-local-variable 'edb-true))) (replace-match (format "%S" decl)))) (let ((make-backup-files nil)) (write-file "edbcore.el")))))) (defun edb-bfunc-make-all () (edb-bfunc-make-edbcore) (let ((dir (car load-path)) (els (edb-bfunc-get-GNUmakefile "installed-el-files"))) (unless (file-directory-p dir) (error "%S is not a directory." dir)) (unless (file-exists-p (expand-file-name "db-util.el" dir)) (error "Could not find db-util.el in %S" dir)) (mapc 'load els) (let ((count 0) source dest fake) (dolist (file (cons "database.el" els)) (setq source (expand-file-name file dir) dest (concat (file-name-sans-versions source) "c")) ;; Compile unless a newer .elc file exists. (if (file-newer-than-file-p dest source) (push dest fake) (byte-compile-file source) (incf count))) ;; If any compilation happens, touch all the old .elc ;; files to fool -- aka "interoperate with" -- make(1). (unless (= 0 count) (apply 'call-process "touch" nil nil nil fake)) (message "Done (Total of %d file%s compiled)" count (if (= count 1) "" "s"))))) ;;; bfuncs ends here edb-1.31/lisp/connection.el0000444000175000017500000006224410745370012014021 0ustar ttnttn;;; connection.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;;; Code: (:edb1 :seq-funcs (make-hash-table :size 3 :test 'eq)) (edb--rput '(:edb1 :seq-funcs) 'read-line (lambda (finish) (let* ((recs (list nil)) (tp recs)) (while (< (progn (nconc tp (list (read (current-buffer)))) (setq tp (cdr tp)) (skip-syntax-forward "^()") (point)) finish)) (cdr recs)))) (edb--rput '(:edb1 :seq-funcs) 'write-line (lambda (b e recs) (goto-char b) (delete-region b e) (let ((out (current-buffer)) (print-escape-newlines t)) (dolist (r recs) (prin1 r out) (princ "\n" out))))) ;; Each entry is an alist that controls how a schema is handled. ;; Valid keys are: ;; ;; :valid-keys -- list of acceptable keys ;; :valid-options -- list of acceptable options ;; :elaborate-value -- function that takes two args: KEY and FORM, ;; and returns FORM elaborated as a value (usually by `eval'ing ;; FORM in a KEY-particular way) ;; :predicates -- list of symbol-predicate pairs; each predicate takes one ;; arg: OBJECT, and returns non-nil if OBJECT fulfills the predicate ;; (:edb1 :schema-schema (make-hash-table :size 3 :test 'eq)) (edb--rput '(:edb1 :schema-schema) 'single `((:valid-keys (:name stringp) (:fields vectorp) (:field-separator string-or-rxvec-p) (:record-separator string-or-rxvec-p) (:record-terminator stringp) (:record-separator-function functionp) (:read-record functionp) (:write-record functionp) (:record-defaults functionp) (:choose-display functionp) :display :report (:summary-format stringp) (:substitutions vectorp) (:every-change-function functionp) (:first-change-function functionp) (:field-order vectorp) (:tagged-setup consp) (:before-display functionp) (:locals vectorp) (:substitution-separators vector-of-two-strings-p) ; [fsep rsep] (:cruft vectorp) ; [[befrec aftrec] [beffld aftfld]] :data) (:valid-options) (:runtime-keys :wraparound :stay-in-edit-mode-p) (:elaborate-value . ,(lambda (key-ignored x) (cond ((and (consp x) (keywordp (car x))) x) ((and (consp x) (stringp (car x))) x) (t (eval x))))) (:predicates (string-or-rxvec-p . ,(lambda (object) (or (stringp object) (and (vectorp object) (let ((len (length object))) (and (memq len '(2 3)) (stringp (aref object 0)) (integerp (aref object 1)) (or (= 2 len) (stringp (aref object 2))))))))) (vector-of-two-strings-p . ,(lambda (object) (and (vectorp object) (= 2 (length object)) (let ((v (aref object 0))) (or (not v) (stringp v))) (let ((v (aref object 1))) (or (not v) (stringp v))))))))) (defun edb--validate-schema (type options schema) (let* ((ent (or (edb--rget '(:edb1 :schema-schema) type) (error "Invalid schema type: %S" type))) (key-specs (cdr (assq :valid-keys ent))) (valid-keys (mapcar (lambda (k-ent) (if (consp k-ent) (car k-ent) k-ent)) key-specs)) (elaborate-value (cdr (assq :elaborate-value ent))) (predicates (let ((local (cdr (assq :predicates ent))) (ht (make-hash-table :test 'eq)) name) (dolist (k-ent key-specs) (when (consp k-ent) (setq name (nth 1 k-ent)) (unless (gethash name ht) (puthash name (or (cdr (assq name local)) name) ht)))) ht)) (valid-options (cdr (assq :valid-options ent)))) ;; check plist form (let ((ls schema)) (while ls (unless (keywordp (car ls)) (error "Not a keyword: %S" (car ls))) (setq ls (cddr ls)))) ;; check key membership (let ((ls schema)) (while ls (unless (memq (car ls) valid-keys) (error "Not a valid key: %S" (car ls))) (setq ls (cddr ls)))) ;; elaborate values (when elaborate-value (let ((ls schema) v new) (while ls (setq v (cadr ls) new (funcall elaborate-value (car ls) v)) (unless (eq new v) (setcar (cdr ls) new)) (setq ls (cddr ls))))) ;; check values (let ((ls schema) k v k-ent pred-name) (while ls (when (setq k (car ls) v (cadr ls) k-ent (assq k key-specs) pred-name (and (consp k-ent) (nth 1 k-ent))) (unless (funcall (gethash pred-name predicates) v) (error "Wrong type for %s (not %s): %S" k pred-name v))) (setq ls (cddr ls)))) ;; check option membership (let ((ls options)) (while ls (unless (memq (car ls) valid-options) (error "Not a valid option: %S" (car ls))) (setq ls (cdr ls))))) schema) (put 'edb--with-callable-connection 'lisp-indent-function 1) (defmacro edb--with-callable-connection (name &rest body) `(flet ((,name (&rest args) (apply ,name args))) ,@body)) (defun edb--connect (control-spec-source) ;; CONTROL-SPEC-SOURCE is either a filename, ;; or a buffer w/ appropriately formatted contents. (let ((conn (lexical-let (V) (lambda (command &rest args) (case command ;; it's not worthy of emacs if it's not extensible (:V! (setq V (apply 'plist-put V args))) (t (plist-get V command)))))) schema) (edb--with-callable-connection conn (with-temp-buffer (let (emacs-lisp-mode-hook) (emacs-lisp-mode)) ;; determine schema metainfo (let ((reality (cond ((bufferp control-spec-source) (insert-buffer-substring control-spec-source) (list (format "(internal from %S)" control-spec-source) (buffer-size))) (t (insert-file-contents control-spec-source)))) meta) (goto-char (point-min)) ;; skip comments and blank lines before identifying cookie (while (and (< (point) (point-max)) (looking-at "[;\n]")) (forward-line 1)) (unless (and (< 4 (cadr reality)) (string= ":EDB " (buffer-substring-no-properties (point) (+ 5 (point)))) (consp (setq meta (progn (goto-char (+ 5 (point))) (read (current-buffer)))))) (error "Does not seem to be an EDB control file")) ;; maintain lameness for the present (unless (and (consp meta) (eq 'single (car meta))) (error "Not lame enough: %S" meta)) (conn :V! :schema-type (car meta)) (conn :V! :schema-options (cddr meta)) (when (setq schema (cadr meta)) (flet ((bad (why) (error "Invalid (%s) schema basis: %S" why schema))) (unless (symbolp schema) (bad "not a symbol")) (unless (boundp schema) (bad "unbound variable")) (setq schema (symbol-value schema)) (unless (or (not schema) (consp schema)) (bad "not a list")) (setq schema (reverse schema))))) ;; determine schema (let (sexp to-eval start kw val) (while (< (progn (while (forward-comment 1)) (point)) (point-max)) (setq start (point) sexp (read (current-buffer))) ;; todo: convert into cond (when (consp sexp) (push sexp to-eval)) (when (keywordp sexp) (push (setq kw sexp) schema) (setq val (read (current-buffer))) (if (memq kw '(:display :report :data)) (let* ((pls (if (eq t val) (list :name t :coding t :EOTB ":EOTB") val)) (datap (eq :data kw)) (tb-start (progn (forward-line 1) (point))) (name (plist-get pls :name)) (coding (or (plist-get pls :coding) t)) (EOTB (or (plist-get pls :EOTB) ":EOTB")) tb-finish) (unless (or ;; data text blocks are anonymous datap (eq t name) (stringp name)) (error "Bad %S name: %S" kw name)) (unless (symbolp coding) (error "Bad %S coding: %S" kw coding)) (unless (stringp EOTB) (error "Bad %S EOTB: %S" kw EOTB)) (setq tb-finish (if (not (re-search-forward (concat "^" EOTB "$") (point-max) 1)) (point-max) (forward-line 1) (match-beginning 0))) (flet ((pl! (prop val) (setq pls (plist-put pls prop val)))) (if datap (let* ((seqr (plist-get pls :seqr)) (f (or (edb--rget '(:edb1 :seq-funcs) seqr) (error "Bad :seqr func: %S" seqr)))) (save-excursion (goto-char tb-start) (pl! :tb-start tb-start) (pl! :tb-finish tb-finish) (pl! :records (funcall f tb-finish)))) (pl! :text (buffer-substring-no-properties tb-start tb-finish)))) (if datap (conn :V! (pop schema) pls) (push pls schema))) (forward-comment 1) (push val schema)))) ;; validate and stash (dolist (form (nreverse to-eval)) (eval form)) (conn :V! :schema (edb--validate-schema (conn :schema-type) (conn :schema-options) (nreverse schema)))))) conn)) ;;;--------------------------------------------------------------------------- ;;; connection file cache (defun edb--connection-file-cache (operation &rest args) (let* ((conn (with-current-buffer (edb--S :ddb-spec) (get-text-property (point-min) :connection))) (schema (edb--with-callable-connection conn (conn :schema))) ;; prevent recursion (inhibit-file-name-handlers (cons 'edb--connection-file-cache inhibit-file-name-handlers)) name desc) (flet ((!! (s) (setq name (substring s (cdr (read-from-string s))) desc (let ((ls schema) look) (while (and (setq ls (memq :display ls) look (cadr ls)) (not (string= (plist-get look :name) name))) (setq ls (cddr ls))) look)))) (case operation ((file-exists-p file-readable-p) (!! (car args)) (not (not desc))) ((insert-file-contents) (!! (car args)) (insert (plist-get desc :text))) ((file-name-directory file-name-nondirectory expand-file-name) (car args)) (t (error "badness!")))))) ;;;--------------------------------------------------------------------------- ;;; 1.x migration (defun edb--1mm<-connection (conn) (let ((schema (funcall conn :schema)) v) (flet ((S (prop) (plist-get schema prop))) (edb--make-v1-monolithic-mess :print-name (S :name) ;; :fieldnames and :recordfieldspecs are set by other means. :field-priorities (when (setq v (S :field-order)) (list (mapcar (lambda (spec) (if (consp spec) spec (list spec))) v))) :record-sepinfo (let* ((cruft (and (S :cruft) (aref (S :cruft) 0))) (bef (and cruft (aref cruft 0))) (brx (and (vectorp bef) (aref bef 0))) (sep (or (S :record-terminator) (S :record-separator))) (srx (and (vectorp sep) (aref sep 0))) (aft (let ((c (and cruft (aref cruft 1)))) (cond ((not c) (S :record-terminator)) ((not (setq v (S :record-terminator))) c) ((vectorp c) (vector (concat (regexp-quote v) (aref c 0)) (aref c 1))) (t (concat v c))))) (arx (and (vectorp aft) (aref aft 0)))) (edb--make-v1-sepinfo :pre-first-string (and (not brx) bef) :pre-first-regexp brx :pre-first-regexp-submatch (and brx (aref bef 1)) :sep-string (if srx (when (= 3 (length sep)) (aref sep 2)) sep) :sep-regexp srx :sep-regexp-submatch (and srx (aref sep 1)) :sep-function (S :record-separator-function) :post-last-string (and (not arx) aft) :post-last-regexp arx :post-last-regexp-submatch (and arx (aref aft 1)))) :field-sepinfo (let* ((cruft (and (S :cruft) (aref (S :cruft) 1))) (bef (and cruft (aref cruft 0))) (brx (and (vectorp bef) (aref bef 0))) (sep (S :field-separator)) (srx (and (vectorp sep) (aref sep 0))) (aft (and cruft (aref cruft 1))) (arx (and (vectorp aft) (aref aft 0)))) (edb--make-v1-sepinfo :pre-first-string (and (not brx) bef) :pre-first-regexp brx :pre-first-regexp-submatch (and brx (aref bef 1)) :sep-string (if srx (when (= 3 (length sep)) (aref sep 2)) sep) :sep-regexp srx :sep-regexp-submatch (and srx (aref sep 1)) ;; sep-function never used, what about the rest? :sep-function nil :post-last-string (and (not arx) aft) :post-last-regexp arx :post-last-regexp-submatch (and arx (aref aft 1)))) :read-record-from-region (S :read-record) :write-region-from-record (let* ((fun (S :write-record)) ;; poor man's (bootstrapping) nm2no (rev (let ((n -1)) (mapcar (lambda (spec) (cons (if (symbolp spec) spec (car spec)) `(aref record ,(incf n)))) (S :fields)))) (arglist (and fun (help-function-arglist fun))) use-let-p) (unless arglist (setq arglist (mapcar 'car rev) use-let-p t)) (cond ((not fun) nil) (use-let-p `(lambda (record) (let ,(mapcar (lambda (fname) `(,fname ,(cdr (assq fname rev)))) arglist) (,fun)))) (t `(lambda (record) (,fun ,@(mapcar (lambda (fname) (cdr (assq fname rev))) arglist)))))) :sub-fieldsep-string (when (setq v (S :substitution-separators)) (aref v 0)) :sub-recordsep-string (when (setq v (S :substitution-separators)) (aref v 1)) :substitutions (when (setq v (S :substitutions)) (append v nil)) :locals (mapcar (lambda (x) (if (consp x) (cons (car x) (cadr x)) (cons x nil))) (S :locals)))))) (defun edb--1format-buffer<-connection (conn) (let* ((schema (edb--with-callable-connection conn (conn :schema))) (mm (edb--1mm<-connection conn)) v form) (flet ((S (prop) (plist-get schema prop)) (maybe-quote (v) (if (or (and (consp v) (memq (car v) '(function lambda))) (stringp v) (vectorp v)) v (list 'quote v))) (ppcur (x) (pp x (current-buffer)) (when (symbolp x) (insert "\n"))) (maybe-pp () (when form (cond ((vectorp form) (insert (format "%s:\n" (aref form 0))) (ppcur (aref form 1))) (t ;; The local variables block must be 3000 ;; chars from the end, so printing things out ;; to be handled "normally" loses on large ;; eval forms. Kludge around by listing all ;; eval forms in a text property. Sigh. (let ((all (get-text-property 1 :eval-forms))) (insert "eval:\n" "(eval (nth " (format "%d" (length all)) " (get-text-property 1 :eval-forms)))\n") (put-text-property (point-min) (point-max) :eval-forms (nconc all (list form))))))))) (set-buffer (get-buffer-create (format " FORMAT FILE: %S" (S :name)))) (fundamental-mode) (erase-buffer) (insert (plist-get (S :display) :text)) (insert "\n") (insert "Local" " " "Variables:\n") ;; fields (when (setq form nil v (S :fields)) (setq form `(database-set-fieldnames-to-list database ',(append v nil)))) (maybe-pp) (when (setq form nil v (S :tagged-setup)) (setq form `(db-tagged-setup ',(cadr v) ,@(cddr v)))) (maybe-pp) ;; monolithic mess (setq form nil) (dolist (slot (mapcar (lambda (x) (intern (format "database-%s" (car x)))) (reverse (get 'edb--v1-monolithic-mess 'cl-struct-slots)))) (unless (memq slot '(database-fieldnames database-recordfieldspecs database-locals database-record-sepinfo database-field-sepinfo)) (when (setq v (funcall slot mm)) (push (maybe-quote v) form) (push `(,slot database) form)))) (when form (push 'setf form)) (maybe-pp) ;; locals (dolist (local (database-locals mm)) (setq form `(database-make-local ',(car local) database ,(cdr local))) (maybe-pp)) ;; fsep and rsep (let ((sep-slots (mapcar (lambda (x) (intern (format "sepinfo-%s" (car x)))) (reverse (get 'edb--v1-sepinfo 'cl-struct-slots))))) ;; fsep (setq form nil) (dolist (slot sep-slots) (when (setq v (funcall slot (database-field-sepinfo mm))) (push (maybe-quote v) form) (push `(,slot sep) form))) (when form (setq form `(let ((sep (database-field-sepinfo database))) (setf ,@form)))) (maybe-pp) ;; rsep (setq form nil) (dolist (slot sep-slots) (when (setq v (funcall slot (database-record-sepinfo mm))) (push (maybe-quote v) form) (push `(,slot sep) form))) (when form (setq form `(let ((sep (database-record-sepinfo database))) (setf ,@form)))) (maybe-pp)) ;; record defaults (when (setq form nil v (S :record-defaults)) (setq form (vector 'db-new-record-function `(lambda (rec db) (let ((nm2no (edb--1D db :nm2no)) (plist (,v))) (while plist (aset rec (gethash (car plist) nm2no) (cadr plist)) (setq plist (cddr plist)))))))) (maybe-pp) ;; before-display stuff (note: clobbered by :choose-display below) (when (setq form nil v (S :before-display)) (setq form (vector 'dbf-before-display-record-function `(lambda (record) (,v ,@(mapcar (lambda (field) `(db-record-field record (quote ,field))) (help-function-arglist v))))))) (maybe-pp) ;; first and every change (when (setq form nil v (S :first-change-function)) (setq form (vector 'dbf-first-change-function v))) (maybe-pp) (when (setq form nil v (S :every-change-function)) (setq form (vector 'dbf-every-change-function v))) (maybe-pp) ;; summary (when (setq form nil v (S :summary-format)) (setq form `(dbf-set-summary-format ,v))) (maybe-pp) ;; multiple display formats (when (setq form nil v (let ((sch (edb--with-callable-connection conn (conn :schema))) acc) (while (setq sch (cdr (memq :display sch))) (push (pop sch) acc)) acc)) (setq form (vector 'dbf-format-name-spec-alist (mapcar (lambda (pl) (let ((name (plist-get pl :name))) (cons name (or (plist-get pl :file) (format "(connection)%s" name))))) v)))) (maybe-pp) ;; selecting display format (when (setq form nil v (plist-get (edb--with-callable-connection conn (conn :schema)) :choose-display)) (setq form (vector 'dbf-before-display-record-function `(lambda (record) (db-change-format (,v ,@(mapcar (lambda (field) `(db-record-field record (quote ,field))) (help-function-arglist v)))))))) (maybe-pp) ;; that's it (insert "End:\n") ;; remember your roots! (put-text-property (point-min) (point-max) :connection conn) ;; rv (current-buffer)))) (defun edb--1run-hooks (symbol) (let ((local (cdr (assq symbol (database-locals dbc-database))))) (run-hooks 'local symbol))) (defun edb--1run-hook-with-arg (symbol &rest args) (let ((local (cdr (assq symbol (database-locals dbc-database))))) (apply 'run-hook-with-args 'local args)) (apply 'run-hook-with-args symbol args)) ;;; connection.el ends here edb-1.31/lisp/database.el0000444000175000017500000001514611016452347013431 0ustar ttnttn;;; database.el --- EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; Keywords: EDB, database, forms ;; Version: 1.31 ;; Release-Date: 2008-05-26 ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; EDB is a flexible, customizable database program for Emacs. ;;; Code: (require 'edbcore) (defconst edb-version "1.31") (defun edb-version () "Return a string describing the version of EDB that is running. When called interactively, display the string in the echo area." (interactive) (let ((v (format "EDB %s of 2008-05-26" edb-version))) (when (interactive-p) (message "%s" v)) v)) (defun edb-interact (control data) "Open a connection to the CONTROL (.edb) and DATA files. This should be behave roughly similarly to calling `db-find-file' on the DATA file. CONTROL may be a buffer whose contents are to be parsed as a .edb file. DATA may be nil, in which case the EDB searches for a file whose stem is the same as CONTROL's (or CONTROL's `buffer-file-name' if CONTROL is a buffer), with extension one of \".data\", \".dat\", or \"\" (empty string), in that order." (interactive (flet ((r (p1 p2) (let ((filename (read-file-name (format "%s file (type RET %s): " p1 p2) nil ""))) (unless (string= "" filename) filename)))) (list (or (r "Control" "for this buffer") (current-buffer)) (r "Data" "to have EDB search for it")))) (let* ((conn (edb--connect control)) (bufferp-control (bufferp control)) (c-type (if bufferp-control 'buffer 'file)) (c-name (if bufferp-control (buffer-name control) control)) (c-fname (if bufferp-control (buffer-file-name control) control)) (ddb-spec (edb--1format-buffer<-connection conn)) (inherent (edb--with-callable-connection conn (conn :data))) (inh-name (when inherent (or c-fname c-name))) priorp database data-display-buffer) (when inherent (if data (db-message "Ignoring inherent data, using instead: %s" data) (setq data (plist-get inherent :records))) (plist-put inherent :records nil)) (unless data (setq data (when c-fname (let ((stem (file-name-sans-extension c-fname))) (flet ((try (ext) (let ((f (concat stem ext))) (when (file-exists-p f) f)))) (or (try ".data") (try ".dat") (try ""))))))) (unless data (kill-buffer ddb-spec) (error "Could not find data source")) (when (and (setq database (db-find-read-in-database (if inherent inh-name data))) (not (edb--1D database :ddbufs))) (setq database nil)) (when (and database ddb-spec) (let ((bufs (edb--1D database :ddbufs))) (while bufs (if (eq ddb-spec (with-current-buffer (car bufs) (edb--S :ddb-spec))) (setq data-display-buffer (car bufs) bufs nil) (setq bufs (cdr bufs)))))) (if database (setq priorp t) (setq database (db-read-database-file (if inherent (cons inh-name data) data) ddb-spec))) (unless data-display-buffer (setq data-display-buffer (car (edb--1D database :ddbufs)))) (switch-to-buffer data-display-buffer) (edb--S! :ddb-spec ddb-spec) (setq dbc-database database) (if priorp (message "(Re-using established connection.)") (when inherent (edb--mputhash (edb--rinit (list :edb1 :1singles database) :inherent :size 7 :test 'eq) :control-type c-type :control-name c-name :control-fname c-fname :seqw (plist-get inherent :seqw) :start-box (cdr (plist-member inherent :tb-start)) :finish-box (cdr (plist-member inherent :tb-finish))) (rename-buffer (concat (if (eq 'file c-type) (file-name-nondirectory c-name) c-name) " (inherent)"))) (db-first-record)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Autoloads ;;; ;;; db-rdb.el (autoload 'db-rdb-setup "db-rdb" "Prepare EDB to read files in RDB format." t) ;;; db-sort.el (autoload 'database-sort "db-sort" "Sort and return DATABASE, which is also side-effected." t) (autoload 'database-sort-interface "db-sort") ;;; db-two-dbs.el (autoload 'db-process-two-databases "db-two-dbs") (autoload 'db-merge "db-two-dbs" "Merge two read-in databases." t) (autoload 'databases-compatible "db-two-dbs") ;;; db-search.el (autoload 'db-parse-match-pattern "db-search") ; should be called first (autoload 'db-print-match-pattern "db-search") (autoload 'db-match "db-search") ;;; db-tagged.el (autoload 'db-tagged-setup "db-tagged" "Prepare EDB to read files in tagged format." t) ;;; lisp/edb-meta.el (autoload 'edb-meta "edb-meta" "Summarize EDB state in a new buffer." t) ;;; lisp/edb-1int-to-single.el (autoload 'edb-1int-to-single "edb-1int-to-single" "Translate EDB 1.x \"internal format\" to a \"single\" schema-schema." t) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; One-time setup ;;; (when (string-match "Lucid" emacs-version) (put 'emacs-version 'edb-running-lemacs t) (load "db-lemacs")) (add-hook 'kill-buffer-hook 'db-kill-buffer-hook) (provide 'database) ;;; database.el ends here edb-1.31/lisp/db-file-io.el0000444000175000017500000016726411016056776013613 0ustar ttnttn;;; db-file-io.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Read and write database files. ;;; Code: (require 'pp) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; DB variables ;;; (defvar db-format-file-path nil "List of directories (strings) to search, in order, for format files not found in the directory with their associated databases.") (defvar db-aux-file-path nil "List of directories (strings) to search, in order, for auxiliary files not found in the directory with their associated databases.") (put 'db-before-read-hooks 'safe-local-variable 'edb-hookp) (defvar db-before-read-hooks nil "Normal hook run immediately before a database is first read but after all local variables are set. The hooks are run in the data display buffer with variable `database' bound. Variable `db-buffer' is bound to a buffer containing the database file. This is a global variable. If you set it to be specific to a particular database \(for instance, in the format or auxiliary file\), then consider having its last action be to reset the variable to nil.") (put 'db-after-read-hooks 'safe-local-variable 'edb-hookp) (defvar db-after-read-hooks nil "Function or list of functions run after a database is completely read. The hooks are run in the data display buffer with variable `database' bound. For databases with nonregular layouts, you might put a call to `database-stored->actual' here, for instance. This is a global variable. If you set it to be specific to a particular database \(for instance, in the format or auxiliary file), then consider having its last action be to reset the variable to nil.") (defvar db-format-file-suffixes '(".dbf" ".fmt" "f") "List of format file suffixes; the basename is that of the database file. The suffixes are tried in order; the default is \(\".dbf\" \".fmt\" \"f\"). The . that may precede the extension must be specified explicitly.") (defvar db-aux-file-suffixes '(".dba" ".aux" "a") "List of auxiliary file suffixes; the basename is that of the database file. The suffixes are tried in order; the default is \(\".dba\" \".aux\" \"a\"). The . that may precede the extension must be specified explicitly.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Internal variables ;;; ;; These have docstrings so docstring-substitute will recognize them. (eval-when-compile (defvar db-buffer nil "Buffer containing a database file being read.")) (eval-when-compile (defvar database nil "Database being read from a file; also other uses.")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Read a database file ;;; (defun db-read-database-file (source &optional display-template confirm) ;; Return the database. The data display buffer will be the first element ;; of the :ddbufs list in the global hash. ;; ;; SOURCE is either a filename (string), or a list: (FILENAME RECORD...), ;; the latter indicating inherent data. ;; ;; Optional arg DISPLAY-TEMPLATE is one of the following: ;; - buffer containing the format to use; ;; - filename that specifies the format file; ;; - nil, in which case the one computed from `db-format-file-path' and ;; `db-format-file-suffixes' will be used, or the user will be prompted ;; for one. ;; ;; If optional prefix arg CONFIRM is non-nil, then no default will be used ;; without confirmation from the user. (edb--G! :io-error-p nil) (with-temp-buffer (let ((buf (current-buffer)) (known-records (when (consp source) (cdr source))) (db-file (when (stringp source) source)) (format-file (when (stringp display-template) display-template)) ddb database coding) ;; sanity check: mutual exclusivity (assert (= 1 (logxor (if known-records 1 0) (if db-file 1 0)))) (when db-file (if (file-exists-p db-file) (insert-file-contents db-file nil) (message "New database file."))) (setf database (or (db-read-database-internal-file-layout) (edb--make-v1-monolithic-mess))) (edb--meta1D database) (edb--1D! database :file (if known-records (propertize "(inherent)" :file (car source)) db-file)) (edb--1D! database :modifiable-p (if known-records t ; hack (file-writable-p db-file))) (when (and (not (bufferp display-template)) (or (not format-file) confirm)) (setq format-file (db-choose-format-file database format-file confirm))) (setq ddb (db-setup-data-display-buffer (or format-file display-template) database t)) (let ((ddbufs (edb--1D database :ddbufs))) (edb--1D! database :ddbufs (cons ddb ddbufs))) (with-current-buffer ddb ;; reread data if coding system is different (when (and (boundp 'edb-data-coding) (setq coding (symbol-value 'edb-data-coding))) (db-message "edb-data-coding: %s" coding) (setq buffer-file-coding-system coding) (with-current-buffer buf (unless (eq buffer-file-coding-system coding) (erase-buffer) (let ((coding-system-for-read coding)) (insert-file-contents db-file nil)) ;; hack! -- fixme: separate internal layout check/read, to ;; avoid ugliness that is the undo/redo. --ttn (when (edb--1D database :togp) (kill-buffer (car (edb--1D database :ddbufs))) (setf database (db-read-database-internal-file-layout)) (edb--1D! database :file db-file) (edb--1D! database :modifiable-p (file-writable-p db-file)) (setq ddb (db-setup-data-display-buffer (or format-file display-template) database t)) (let ((ddbufs (edb--1D database :ddbufs))) (edb--1D! database :ddbufs (cons ddb ddbufs))) (with-current-buffer ddb (setq buffer-file-coding-system coding))))))) (with-current-buffer ddb (let ((db-buffer buf)) (run-hooks 'db-before-read-hooks))) (if known-records (edb--snap! database (length known-records) known-records) (db-read-database-file-helper database)) (with-current-buffer ddb (run-hooks 'db-after-read-hooks)) database))) (defun db-read-database-internal-file-layout () ;; If the buffer contains a database in internal file layout, read and ;; return the header portion (not the records). Otherwise, return nil. (when (db-skip-string-forward ";; Database file written by EDB") (let ((here (point)) (emacs-lisp-mode-hook nil) cruft) (emacs-lisp-mode) ;; Update old formats in small increments. (when (db-skip-string-forward "; format 0.1") (delete-char -1) (insert "2") (forward-sexp) (backward-char 1) ;; add locals slot to database (insert " nil") (goto-char here)) (when (db-skip-string-forward "; format 0.2") (delete-char -1) (insert "3") (forward-sexp) (backward-char 1) (backward-sexp 1) (backward-char 1) ;; add modified bit to database (insert " nil") (goto-char here)) (when (db-skip-string-forward "; format 0.3") (delete-char -1) (insert "4") (down-list 1) (forward-sexp 16) ;; add "internal file layout" slot to database (insert " t") (forward-sexp 14) ;; add modifiable bit to database (insert " t") (goto-char here)) (when (db-skip-string-forward "; format 0.4") (delete-char -1) (insert "5") ;; change "[database" to "[cl-struct-database" (down-list 1) (insert "cl-struct-") (forward-sexp 17) ;; change "[sepinfo" to "[cl-struct-sepinfo" (down-list 1) (insert "cl-struct-") (up-list 1) (down-list 1) (insert "cl-struct-") (up-list 1) (down-list 1) (insert "cl-struct-") (goto-char here)) (flet ((skip-zonk (s z) (let ((p (progn (forward-sexp s) (point)))) (forward-sexp z) (delete-region p (point))))) (when (db-skip-string-forward "; format 0.5") (delete-char -1) (insert "6") ;; Remove five slots for quotation information. (down-list 1) (skip-zonk 24 5) (goto-char here)) (when (db-skip-string-forward "; format 0.6") (delete-char -1) (insert "7") (down-list 1) ;; Remove structure tag. (skip-zonk 0 1) ;; Remove slots for data container, number of records, filename, ;; "file-local" variables, aux filename, buffer list, default format ;; filename (but keep as cruft), hide functions, number of fields. (skip-zonk 1 6) (let ((filename (read (current-buffer)))) (when filename (push (cons :format-file filename) cruft))) (skip-zonk -1 3) ;; Remove slot for field name to number alist. (skip-zonk 1 1) ;; Remove slots for "hidden to end" and "internal file layout" bits. (skip-zonk 2 2) ;; Remove structure tags. (down-list 1) (skip-zonk 0 1) (backward-up-list 1) (forward-sexp 1) (down-list 1) (skip-zonk 0 1) (backward-up-list 1) ;; Remove slot for alternatives sepinfo. (skip-zonk 1 1) ;; Remove slots for mod bits. (skip-zonk 5 2) ;; Delete parens around record data. (re-search-forward "^($") (delete-region (1- (match-beginning 0)) (match-end 0)) (save-excursion (re-search-forward "^).*$") (delete-region (1- (match-beginning 0)) (match-end 0))) ;; Add cruft. (insert (format "\n%S\n" cruft)) (goto-char here))) ;; Don't forget to change `db-write-1' when updating the format number. (unless (db-skip-string-forward "; format 0.7") (db-message "I don't know if I can read the database, but I'll try")) (end-of-line) (let ((rv (read (current-buffer))) (cruft (read (current-buffer)))) (edb--meta1D rv) (edb--1D! rv :togp t) (when cruft (edb--1D! rv :1CRUFT cruft)) ;; Deconstruct so that `database-set-fieldnames-to-list' ;; can elaborate (after reconstructing). Ugly shit! (let* ((names (database-fieldnames rv)) (count (length names)) (types (database-recordfieldspecs rv)) name type) (setf (database-fieldnames rv) nil (database-recordfieldspecs rv) nil) (database-set-fieldnames-to-list rv (mapcar (lambda (fidx) (if (setq name (aref names fidx) type (aref types fidx)) (cons name type) name)) (number-sequence 0 (1- count))))) ;; TODO: Factor this and same in `db-setup-data-display-buffer'. (unless (database-field-priorities rv) (setf (database-field-priorities rv) (list (mapcar 'list (number-sequence 0 (1- (length (database-fieldnames rv)))))))) rv)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Format file ;;; (defun db-locate-format-file (filename) ;; Return a full pathname for the format file named FILENAME, or err. (or (db-locate-readable-file-prefer-cwd (file-name-nondirectory filename) db-format-file-path) (error "I can't find a format file named %s." filename))) (defun db-choose-format-file (db ff-default confirm) ;; Return a format file according to DB or FF-DEFAULT. ;; Prompt if CONFIRM is set or if we can't get one from DB alone. (let* ((db-file (edb--1D db :file)) (default (or ff-default (cdr (assq :format-file (edb--1D db :1CRUFT))) (db-locate-readable-file-prefer-cwd (file-name-nondirectory (file-name-sans-extension db-file)) (cons (file-name-directory db-file) db-format-file-path) db-format-file-suffixes)))) (if (and default (not confirm)) (let* ((dir (file-name-directory db-file)) (default-directory (if dir (expand-file-name dir) default-directory))) (db-locate-format-file default)) ;; Don't need `db-locate-format-file' because MUSTMATCH arg ;; to `read-file-name' is t. (expand-file-name (read-file-name (if default (format "Display format for %s: [default %s] " (file-name-nondirectory db-file) (file-name-nondirectory default)) (format "Display format for %s: " (file-name-nondirectory db-file))) (file-name-directory db-file) (when default (expand-file-name default (file-name-directory db-file))) t))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Read database file: helper functions ;;; (defun db-read-database-file-helper (db) ;; Read current buffer into database DB and return DB. (db-message "Reading database...") ;; The format and the auxiliary file should already be loaded; ie, all ;; special variables should be set. (if (edb--1D db :togp) (let* ((new (list nil)) (tp new) (count 0)) (while (progn (skip-chars-forward " \n") (< (point) (point-max))) (setcdr tp (list (read (current-buffer)))) (setq count (1+ count) tp (cdr tp))) (edb--snap! db count (cdr new))) (database-io-setup db t) ;; Remove pre-first-record- and post-last-record strings or regexps, then ;; add a record separator to the end so that every record is terminated by ;; one. Try the {pre-first,post-last}-regexp first. On match, save the ;; text in the associated {pre-first,post-last}-string for output later. (let ((rsep (database-record-sepinfo db)) rgx str p) ;; Remove gubbish before first record. (goto-char (point-min)) (when (setq p (cond ((setq rgx (sepinfo-pre-first-regexp rsep)) (unless (db-skip-regexp-forward rgx) (error "Unmatched pre-first regexp")) (match-end (sepinfo-pre-first-regexp-submatch rsep))) ((setq str (sepinfo-pre-first-string rsep)) (unless (db-skip-string-forward str) (error "Missing pre-first string")) (point)) (t nil))) (if rgx (setf (sepinfo-pre-first-string rsep) (delete-and-extract-region (point-min) p)) (delete-region (point-min) p))) ;; Remove gubbish after last record. (goto-char (point-max)) (when (setq p (cond ((setq rgx (sepinfo-post-last-regexp rsep)) (unless (re-search-backward rgx) (error "Unmatched post-last regexp")) (match-beginning (sepinfo-post-last-regexp-submatch rsep))) ((setq str (sepinfo-post-last-string rsep)) (unless (search-backward str) (error "Missing post-last string")) (point)) (t nil))) (if rgx (setf (sepinfo-post-last-string rsep) (delete-and-extract-region p (point-max))) (delete-region p (point-max)))) ;; If there isn't one there already, add a final record separator so ;; that every record is terminated by one. (let ((sep (sepinfo-sep-string rsep))) (unless (db-skip-string-backward sep) (insert sep)))) (if (database-read-record-from-region db) (db-read-file-custom db) (db-read-file-delimited db))) (edb--meta1D db) (db-message "Reading database...done (%d records)" (edb--1D db :nrecords)) db) (defun edb--snap! (db len ls) ;; Take a list of records and set DB's `:vov' and `:nrecords'. (let ((vov (make-vector (+ len 10) nil))) (dotimes (i len) (aset vov i (pop ls))) (edb--1D! db :vov vov) (edb--1D! db :nrecords len))) (defmacro db-reading-noninternal (condition &rest body) (declare (indent 1) (debug (form body))) `(let* ((new (list nil)) (tp new) (count 0) ; binding used in BODY this-record) ; value set by BODY (while ,condition (setq count (1+ count)) ;; Noisy, obscures warning messages. (if (and db-inform-interval (zerop (% count db-inform-interval))) (message "Reading database...%d" count)) ,@body ; uses binding `database' (setcdr tp (list this-record)) (setq tp (cdr tp))) (edb--snap! db count (cdr new)))) ;; fixme: integrate and refactor db-read-file-* funcs. --ttn (defun db-read-file-custom (db) (let ((rrfunc (database-read-record-from-region db)) (nfields (length (database-fieldnames db))) (nm2no (edb--1D db :nm2no)) (rsi (database-record-sepinfo db)) ;; documented dynamic binding (database db)) ;; Uses `database-read-record-from-region' and `sepinfo-sepfunc' from ;; `database-record-sepinfo'. ;; Check that the sepinfo has enough information. (if (sepinfo-sep-regexp rsi) (unless (sepinfo-sep-regexp-submatch rsi) (error "Missing submatch for sep-regexp `%s' of record sepinfo." (sepinfo-sep-regexp rsi))) (unless (sepinfo-sep-function rsi) (let ((sep (sepinfo-sep-string rsi))) (when (or (not sep) (equal "" sep)) (error "Missing specification in record sepinfo.")) (db-jam-si sep rsi)))) (if (sepinfo-sep-function rsi) ;; Use sep-function to delimit the records ;; Return a pair of (end-pos . start-pos). (let ((delim (sepinfo-sep-function rsi)) ;; Read-record-from-region might do insertions or deletions, ;; so just remembering the position isn't enough. next-start-marker (prev-end-pos 'nil) (end-start-pair '(nil))) (goto-char (point-min)) (setq next-start-marker (point-marker)) ;; Assume that there is at least one record in the file. ;; fixme: validate first. --ttn (db-reading-noninternal (marker-position next-start-marker) (setq end-start-pair (funcall delim prev-end-pos)) (narrow-to-region (marker-position next-start-marker) (car end-start-pair)) ;; Writers of record->region often forget to do this. (goto-char (point-min)) (setq this-record (let ((v (funcall rrfunc))) (if (vectorp v) v (db--mkrec nfields nm2no v)))) ;; Not `(car end-start-pair)' in case buffer was modified. (setq prev-end-pos (point-max)) (widen) ;; In 18.55, `set-marker' can only make markers point to the ;; accessible portion of the buffer, so do this after widening. ;; (This may have changed by 18.59.) ;; Don't use just `(cdr end-start-pair)' because the buffer may ;; have been modified. (set-marker next-start-marker (and (cdr end-start-pair) (+ (- (cdr end-start-pair) (car end-start-pair)) prev-end-pos))))) ;; Use regexp to delimit the records. (let ((rsep-rgx (sepinfo-sep-regexp rsi)) (rsep-rgx-subm (sepinfo-sep-regexp-submatch rsi)) (next-start (point-min)) ;; How many characters to skip before looking for the start of the ;; next record. We can't use a position because rrfunc may insert ;; or delete, and we can't use markers because `narrow-to-region' ;; squeezes them. sep-len) ;; The caller also moved point. (goto-char (point-min)) (db-reading-noninternal (< next-start (point-max)) (goto-char next-start) ;; re-search-forward errs if it fails (re-search-forward rsep-rgx) (setq sep-len (- (match-end rsep-rgx-subm) (match-beginning rsep-rgx-subm))) (narrow-to-region next-start (match-beginning rsep-rgx-subm)) (goto-char (point-min)) (setq this-record (let ((v (funcall rrfunc))) (if (vectorp v) v (db--mkrec nfields nm2no v)))) (setq next-start (+ (point-max) sep-len)) (widen)))))) (defun db-read-file-delimited (db) ;; If there are any regexps set in the sepinfos at this point, then we ;; assume that the programmer specified them explicitly; we assume that if ;; any substitutions are requested, then the programmer knows that they ;; won't cause any ambiguities. (goto-char (point-min)) ;; We have now cleared away the pre- and post- garbage. (if (or (sepinfo-sep-regexp (database-field-sepinfo db)) (sepinfo-sep-regexp (database-record-sepinfo db))) ;; Regexps involved, so do no substitution on the separators, except for ;; those that the user has explicitly requested; then read the database. (progn (database-perform-substitutions db t) (db-read-file-delimrx db)) ;; There are no regexps involved. (let* ((fsep-str (database-full-fieldsep-string db)) (rsep-str (database-full-recordsep-string db)) conftup) ;; Convert the database buffer from "complex" to "simple" form. (let* ((fsi (database-field-sepinfo db)) (pre-str (sepinfo-pre-first-string fsi)) (pre-rgx (sepinfo-pre-first-regexp fsi))) ;; Previously, we only did the record separators; ;; here we do the field separators as well. (goto-char (point-min)) (cond (pre-rgx (if (db-skip-regexp-forward pre-rgx) (delete-region (point-min) (point)) (error "Missing regexp `%s' before first field." pre-rgx))) (pre-str (if (db-skip-string-forward pre-str) (delete-region (point-min) (point)) (error "Didn't find string `%s' leading the first field." pre-str)))) (goto-char (point-max)) ;; Don't get rid of post-last-field-regexp or post-last-field-string ;; because we look for them at the end of every record. ;; Make sure that record-sepinfo-sep-string appears at the end. (when (sepinfo-sep-string (database-record-sepinfo db)) (if (db-skip-string-backward (sepinfo-sep-string (database-record-sepinfo db))) (goto-char (point-max)) (insert (sepinfo-sep-string (database-record-sepinfo db))))) (when pre-str (insert pre-str))) ;; We're still inside the big let. ;; This pre-read confirmation should be optional. And it should be ;; able to deal with regexps. ;; When would this test fail? Won't fsep-str and ;; rsep-str always be non-nil when we get here? (when (and fsep-str rsep-str) (db-message "Confirming database format...") (setq conftup (db-confirm-seps fsep-str rsep-str (length (database-fieldnames db)) nil)) (if (or (db-conftup-bad-fsep conftup) (db-conftup-bad-rsep conftup)) (progn (db-warning "The database file is malformed!") (when (db-conftup-bad-fsep conftup) (db-warning "Extra field separator %s found in data." (pp-to-string fsep-str))) (when (db-conftup-bad-rsep conftup) (db-warning "Extra record separator %s found in data." (pp-to-string rsep-str))) ;; show the db warning buffer (if (yes-or-no-p "Bad file format; try reading anyway? ") (db-message "Damaged file; expecting circa %d records" (db-conftup-reccount conftup)) (kill-buffer nil) (error "Aborted attempt to read database."))) (db-message "Database looks OK from here; expecting %d records" (db-conftup-reccount conftup)))) ;; mernst sez: This also sets the io-sep variables. ;; ttn sez: ??? ;; Convert field/record separators (perhaps choosing new ones), so ;; they won't get damaged by the substitution, and then doing the ;; substitution. It also must set the sub-{field,record}sep slots, ;; because later on those fields are slavishly followed. We can't ;; parse or do substitutions if either of the separators is a regexp. (if (or (sepinfo-sep-regexp (database-record-sepinfo db)) (sepinfo-sep-regexp (database-field-sepinfo db))) (setf (database-sub-recordsep-string db) (or (sepinfo-sep-regexp (database-record-sepinfo db)) (database-sub-recordsep-string db) rsep-str) (database-sub-fieldsep-string db) (or (sepinfo-sep-regexp (database-field-sepinfo db)) (database-sub-fieldsep-string db) fsep-str)) (unless rsep-str (error "No record separator specified.")) (if (database-acceptable-delimiter-p db rsep-str) (setf (database-sub-recordsep-string db) rsep-str) (db-message "Substituting record delimiter for read...") (setf (database-sub-recordsep-string db) (database-generate-delimiter db)) (goto-char (point-min)) (let ((s (database-sub-recordsep-string db))) (while (search-forward rsep-str nil t) (replace-match s nil t))) (setq fsep-str (replace-regexp-in-string rsep-str (database-sub-recordsep-string db) fsep-str)) (db-message "Substituting record delimiter for read...done")) (if (or (database-acceptable-delimiter-p db fsep-str) (database-read-record-from-region db)) (progn (db-message "fsep-str `%s' acceptable because `(or %s %s)'" (string-to-list fsep-str) (database-acceptable-delimiter-p db fsep-str) (database-read-record-from-region db)) (setf (database-sub-fieldsep-string db) fsep-str)) (unless fsep-str (error "No field separator specified.")) (db-message "Substituting field delimiter for read...") (setf (database-sub-fieldsep-string db) (database-generate-delimiter db)) (db-message "Substituting field delimiter... (`%s' for `%s')" (string-to-list (database-sub-fieldsep-string db)) (string-to-list fsep-str)) (goto-char (point-min)) (let ((s (database-sub-fieldsep-string db))) (while (search-forward fsep-str nil t) (replace-match s nil t))) (db-message "Substituting field delimiter for read...done")) (db-message "sub-fieldsep: %s" (string-to-list (database-sub-fieldsep-string db))) (database-perform-substitutions db t)) (db-read-file-delimstr db)))) (defun db-read-file-delimstr (db) ;; When we call this, the database is in the following form: ;; Point at start of first field of first record. ;; Each field, except last, is ended by actual-fieldsep. ;; Each record, including last, is ended by actual-recordsep. ;; End of last recordsep-string = eob. ;; Field-sep and record-sep must be strings. (db-message "Reading database...") (goto-char (point-min)) (let* ((fsep (database-sub-fieldsep-string db)) (rsep (database-sub-recordsep-string db)) (flen (length fsep)) (rlen (length rsep)) (nfields (length (database-fieldnames db))) (max-fno (1- nfields)) (default-slice (db-rs-slice db 'edb--1rs-default-value)) (here (point)) fno end-of-rsep end-of-record) (db-reading-noninternal (not (or (eobp) ;; Does this cause any problems? ;; Special case for rsep = "\n\n", ;; extra newline at end (and (string= rsep "\n\n") (looking-at "\n\\'")))) (setq this-record (make-vector nfields nil)) (if (search-forward rsep nil t) (setq end-of-rsep (point) end-of-record (- (point) rlen)) (db-warning "Didn't find %s at end of last field of record %d, %s!" (pp-to-string rsep) count "and I put it there myself") (setq end-of-rsep (point-max) end-of-record (point-max))) (goto-char here) (setq fno 0) (while (< fno max-fno) ;; fixme: trap errors, maybe check for rsep in field data. --ttn (if (search-forward fsep end-of-record t) (progn (aset this-record fno (buffer-substring here (- (point) flen))) (setq here (point)) (incf fno)) (db-warning "%s %d fields of record %d (didn't find fsep %s)" "Hit the end of the record after" fno count (pp-to-string fsep)) (aset this-record fno (buffer-substring here end-of-record)) (setq here end-of-record) (incf fno) (while (<= fno max-fno) (aset this-record fno (aref default-slice fno)) (incf fno)))) ;; Weren't too few fields, so set the last one (else it's already set). (when (= fno max-fno) (when (search-forward fsep end-of-record t) (db-warning "Extra fields in record %d %s." count "packed into the last field; beware when writing") (edb--G! :io-error-p t)) (aset this-record max-fno (buffer-substring here end-of-record))) (goto-char end-of-rsep) (setq here (point))) ;; Convert from stored to actual format. (database-stored->actual db) ;; Function is called for side-effect, but return the database anyway. db)) (defun db-read-file-delimrx (db) (db-message "Reading database...") (goto-char (point-min)) (let* ((fsi (database-field-sepinfo db)) (rsi (database-record-sepinfo db)) (frx (or (sepinfo-sep-regexp fsi) (regexp-quote (sepinfo-sep-string (database-field-sepinfo db))))) (frx-subm (or (sepinfo-sep-regexp-submatch fsi) 0)) (rrx (or (sepinfo-sep-regexp rsi) (regexp-quote (sepinfo-sep-string rsi)))) (rrx-subm (or (sepinfo-sep-regexp-submatch rsi) 0)) ;; Do not fold into `rrx'; they may have submatches of their own. (pre-str (sepinfo-pre-first-string fsi)) (pre-frx (or (sepinfo-pre-first-regexp fsi) (and pre-str (regexp-quote pre-str)))) (pre-frx-subm (or (sepinfo-pre-first-regexp-submatch fsi) 0)) (post-str (sepinfo-post-last-string fsi)) (post-frx (or (sepinfo-post-last-regexp fsi) (and post-str (regexp-quote post-str)))) (post-frx-subm (or (sepinfo-post-last-regexp-submatch fsi) 0)) (nfields (length (database-fieldnames db))) (max-fno (1- nfields)) (here (point)) fno end-of-rrx end-of-record) (db-reading-noninternal (not (eobp)) (setq this-record (make-vector nfields nil)) (when pre-frx (if (db-skip-regexp-forward pre-frx) (progn (setq here (match-end pre-frx-subm)) (goto-char here)) (error "Didn't find pre-first stuff I expected."))) (setq fno 0) (while (< fno max-fno) ;; fixme: trap errors, maybe check for rrx in field data. --ttn (if (re-search-forward frx nil t) (progn (aset this-record fno (buffer-substring here (match-beginning frx-subm))) (setq here (match-end frx-subm)) (incf fno)) (db-warning "%s %d fields of record %d (didn't find frx `%s')" "End of data after" fno count frx) (setq fno max-fno))) (if (re-search-forward rrx nil t) (setq end-of-rrx (match-end rrx-subm) end-of-record (match-beginning rrx-subm)) (db-warning "Didn't find %s at end of last field of record %d." (pp-to-string rrx) count) (setq end-of-rrx (point-max) end-of-record (point-max))) (goto-char here) (when (re-search-forward frx end-of-record t) (db-warning "Too many fields in record %d; %s; beware when writing." count "packing them all into the last field") (edb--G! :io-error-p t)) (aset this-record max-fno (buffer-substring here end-of-record)) (goto-char end-of-rrx) (setq here (point))) (database-stored->actual db) db)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Read database utilities ;;; (defun database-stored->actual (&optional db) ;; Convert string values in a newly-read database to the actual format. If ;; DB is not specified, use the value of the dynamic variable `database'. ;; This makes it possible to be put directly in `db-after-read-hook'. (unless db (setq db database)) (let* ((no-of-fields (length (database-fieldnames db))) (convert (make-vector no-of-fields nil)) (s->a-slice (db-rs-slice db 'edb--1rs-stored->actual)) s->a todo val) (dotimes (fno no-of-fields) (when (setq s->a (aref s->a-slice fno)) (push fno todo) (aset convert fno s->a))) (when todo (db-message "Converting from stored record format...") (db-maprecords (lambda (record) (dolist (fno todo) (setq val (aref record fno)) (aset record fno (if (stringp val) (funcall (aref convert fno) val) val)))) db nil "Converting record format...%s") (db-message "Converting record format...done")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Write database file ;;; (defun db-write-1 () (edb--G! :io-error-p nil) ;; This is called by `db-write-database-file' with the data display buffer ;; current, and we need the values of variables local to that buffer. (let ((orig-buf (current-buffer)) (ofile (edb--1D dbc-database :file)) (inherent (edb--1D dbc-database :inherent)) (db dbc-database) (coding buffer-file-coding-system)) (when (file-directory-p ofile) (edb--G! :io-error-p t) (error "Invalid filename: %s" ofile)) (unless (file-writable-p ofile) (if (and (not noninteractive) (y-or-n-p (concat "File not writable: " ofile "\nMake it writable and continue? "))) (set-file-modes ofile (logior #o200 (file-modes ofile))) (edb--G! :io-error-p t) (error "File not writable: %s" ofile))) (with-temp-buffer (cond ;; Data inherent data to the connection. (inherent (flet ((iget (k) (gethash k inherent)) (bget (k) (car (iget k))) (bput (k v) (setcar (iget k) v))) (let* ((all (db-maprecords 'identity db nil nil t)) (zonkp nil) (cbuf (cond ((eq 'buffer (iget :control-type)) (get-buffer (iget :control-name))) ((find-buffer-visiting (iget :control-fname))) (t (setq zonkp t) (find-file (iget :control-fname)))))) (unless cbuf (error "Control no longer exists for %S" (buffer-name orig-buf))) (with-current-buffer cbuf (save-excursion (funcall (edb--rget '(:edb1 :seq-funcs) (iget :seqw)) (bget :start-box) (bget :finish-box) all) (bput :finish-box (point))) (if (not (setq ofile (iget :control-fname))) (db-message "Buffer %S updated (but not written to a file)" (iget :control-name)) (unless (file-writable-p ofile) (error "File not writable: %s" ofile)) (when (file-directory-p ofile) (error "Invalid filename: %s" ofile)) (write-file ofile) (when zonkp (kill-buffer nil))) (database-set-modified-p db nil))))) ;; "Internal" representation -- sigh. ((edb--1D db :togp) (let ((standard-output (current-buffer))) (setq buffer-file-coding-system coding) (insert ";; Database file written by EDB; format 0.7") (let ((coding-string (symbol-name coding))) (unless (string-match "^undecided-" coding-string) (insert " -*- coding: " coding-string "; -*-"))) (insert "\n") (let ((copy (edb--copy-v1-monolithic-mess db)) (nfields (length (database-fieldnames db))) (prios (database-field-priorities db))) (setf (database-field-priorities copy) (if (equal (list (mapcar 'list (number-sequence 0 (1- nfields)))) prios) nil prios)) (pp copy)) (let ((cruft (edb--1D db :1CRUFT))) ; blech (if cruft ; even more blech (pp cruft) (insert "nil\n"))) (db-maprecords 'pp db) ;; This is not catching the error raised by basic-save-buffer if ;; the destination is not writable. (condition-case error (let ((require-final-newline nil) ;; get around write-file (auto-save-default nil)) (write-file ofile) (database-set-modified-p db nil)) ;; Used to be `file-error', which didn't catch the error raised ;; by `basic-save-buffer' if the destination is not writable. (error (edb--G! :io-error-p t) ;; This must come before the buffer is killed. (db-warning "Error `%s' while writing buffer %s to file %s." error (buffer-name orig-buf) ofile))))) ;; Don't use internal representation. (t (db-copy-buffer-local-variables orig-buf ;; We don't want to be *exactly* ;; like the data display buffer. 'major-mode 'buffer-read-only) (database-io-setup db) (let ((first-record t) (rsep (database-record-sepinfo db))) (when (sepinfo-pre-first-string rsep) (insert (sepinfo-pre-first-string rsep))) (if (database-write-region-from-record db) ;; Don't check separators for write-record-function, even for ;; recordsep; read-record-function's cleverness is unknown albeit ;; not unknowable. Also, don't do substitution or quoting. (let ((record-sep-string (sepinfo-sep-string rsep)) (write-region-fn (database-write-region-from-record db)) ;; documented dynamic binding (database db)) (db-message "Writing database...") (db-maprecords (lambda (record) (if first-record (setq first-record nil) (insert record-sep-string)) (funcall write-region-fn record)) db nil "Writing database...%d") (db-message "Writing database to disk...")) (db-write-intdelim db)) (when (sepinfo-post-last-string rsep) (insert (sepinfo-post-last-string rsep))) (condition-case error (let ((require-final-newline nil) ;; get around `write-file' (auto-save-default nil)) (write-file ofile) (database-set-modified-p db nil)) ;; Used to be `file-error', which didn't catch the error raised ;; by `basic-save-buffer' if the destination is not writable. (error (edb--G! :io-error-p t) ;; This must come before the buffer is killed. (db-warning "Error `%s' while writing buffer %s to file %s." error (buffer-name orig-buf) ofile)))))))) ;; Update. (when (or (db-data-display-buffer-p) (db-summary-buffer-p)) (force-mode-line-update))) (defun db-write-intdelim (db) ;; Insert the records, fields separated by fieldsep and records separated by ;; recordsep, into the current buffer; it uses delimited format. This is ;; called by `db-write-1', which arranges `unwind-protect' boundaries, calls ;; the -internal function that uses the proper output file layout, etc. (let* ((previous-point (point)) (first-record t) (no-of-fields (length (database-fieldnames db))) (fsep (database-full-fieldsep-string db)) (rsep (database-full-recordsep-string db)) (sub-fsep (or (database-sub-fieldsep-string db) fsep)) (sub-rsep (or (database-sub-recordsep-string db) rsep)) (a->s-slice (db-rs-slice db 'edb--1rs-actual->stored)) conftup) ;; Check the delimiters. (unless (database-acceptable-delimiter-p db sub-fsep) (setq sub-fsep (database-generate-delimiter nil))) (unless (database-acceptable-delimiter-p db sub-rsep) (setq sub-rsep (database-generate-delimiter nil))) (db-message "Writing database...") (db-maprecords (lambda (record) (dotimes (fno no-of-fields) (when (> fno 0) (insert sub-fsep)) ;; This is `record-field-stored', inlined. (insert (let ((a->s (aref a->s-slice fno)) (val (aref record fno))) (if a->s (funcall a->s val) val)))) (insert sub-rsep)) db nil "Writing database...%d") (db-message "Writing database...confirming") (narrow-to-region previous-point (point-max)) (setq conftup (db-confirm-seps sub-fsep sub-rsep (length (database-fieldnames db)) (edb--1D db :nrecords))) (if (or (db-conftup-bad-fsep conftup) (db-conftup-bad-rsep conftup)) (progn (when (db-conftup-bad-fsep conftup) (db-warning "Unexpected field separator %s in data; %s." (pp-to-string sub-fsep) "trying again") (setf (database-sub-fieldsep-string db) (database-generate-delimiter db t))) (when (db-conftup-bad-rsep conftup) (db-warning "Unexpected record separator %s in data; %s." (pp-to-string sub-rsep) "trying again") (setf (database-sub-recordsep-string db) (database-generate-delimiter db t))) ;; We've chosen new separators; erase the work so far. (delete-region previous-point (point)) ;; Call this function recursively. (db-write-intdelim db) ;; I've called this recursively; don't do any substitution ;; or quoting. ) ;; Confirmation was OK: correct number of field and record ;; separators found. ;; Put off adding the pre- and post- field strings until ;; after checking separators, as they may contain anomolous ;; field separators, for instance. ;; But do it before substitution so that all field pre- and ;; post- strings are treated identically. ;; The whole point of using io-separators is so they ;; appear exactly as the user specified, unaffected by ;; substitution. ;; But note that pre- and post- record strings will be added ;; later, after substitution. ;; Do the substitution, then, if field separators were changed in order ;; to prevent them from getting damaged by the substitution, convert ;; them back to the user-specified strings, which might contain ;; substrings that would have been substituted for in the previous ;; operation, had we not been careful. ;; Check that there are the correct number of fieldseps and recordseps ;; here; if wrong number, choose new fieldsep and/or recordsep and take ;; it from the top. (database-perform-substitutions db nil) (unless (equal sub-fsep fsep) (goto-char (point-min)) (while (search-forward sub-fsep nil t) (replace-match fsep nil t))) (unless (equal sub-rsep rsep) (goto-char (point-min)) (while (search-forward sub-rsep nil t) (replace-match rsep nil t))) ;; Now the buffer is ready to have the preceding and trailing junk ;; added and to be written to disk. ;; Convert from "simple" to "complex" form. (goto-char (point-min)) (let ((pre-first (sepinfo-pre-first-string (database-field-sepinfo db)))) (when pre-first (insert pre-first))) (goto-char (point-max)) (if (and (db-skip-string-backward (or (sepinfo-pre-first-string (database-field-sepinfo db)) "")) (db-skip-string-backward (or (sepinfo-sep-string (database-record-sepinfo db)) ""))) (delete-region (point) (point-max)) (error "Didn't find expected trailing junk `%s' or `%s'." (sepinfo-pre-first-string (database-field-sepinfo db)) (sepinfo-sep-string (database-record-sepinfo db))))) (widen))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; I/O utilities ;;; (defun database-io-setup (db &optional norx) (flet ((bad (part s name) (error "Need a submatch to go with %s-regexp `%s' of %s." part s name)) (chk (si name sdef) ;; It's good that this setting of -regexp slots doesn't happen ;; until the last possible moment, when quotation-char and other ;; variables that these values depend on are already set to ;; their final values. ;; If the string is the empty string, then we must have just set ;; it that way, which means that we either also just set the ;; regexp to nil, or we set the regexp to something we care ;; about. In either case don't mess further with the regexp. ;; The submatches could default to 0 if they're nil; but I want ;; to be more paranoid than that. (when (equal "" (sepinfo-pre-first-string si)) (setf (sepinfo-pre-first-string si) nil)) (cond ((sepinfo-pre-first-regexp si) (unless (sepinfo-pre-first-regexp-submatch si) (bad 'pre-first (sepinfo-pre-first-regexp si) name))) ((and (sepinfo-pre-first-string si) (not norx)) (db-jam-si pre-first si))) ;; Don't test for sep-function because the sepinfo must be valid ;; for output as well as input. On the other hand, we don't ;; need sep-string to be set if a wrfr function is in use, but ;; this function doesn't do any such checks. (when (or (not (sepinfo-sep-string si)) (and (equal "" (sepinfo-sep-string si)) (not (sepinfo-sep-regexp si)))) (setf (sepinfo-sep-string si) sdef)) (cond ((sepinfo-sep-regexp si) (unless (sepinfo-sep-regexp-submatch si) (bad 'sep (sepinfo-sep-regexp si) name))) ((and (not (sepinfo-sep-function si)) (not norx)) (db-jam-si sep si))) (when (equal "" (sepinfo-post-last-string si)) (setf (sepinfo-post-last-string si) nil)) (cond ((sepinfo-post-last-regexp si) (unless (sepinfo-post-last-regexp-submatch si) (bad 'post-last (sepinfo-post-last-regexp si) name))) ((and (sepinfo-post-last-string si) (not norx)) (db-jam-si post-last si))))) ;; Some of this information may already be correctly set (especially if ;; we're now writing), but just in case some of the database slots have ;; changed since reading. ;; When converting strings to regexps, must be careful to watch out for ;; substitution and quotation; don't get fooled. ;; When writing to the file, we take the previous version's local ;; variables section verbatim. ;; We're only setting the regexp variables. ;; When reading, we'll get the variables from the database, auxiliary, ;; and format files anew each time anyway. (chk (database-record-sepinfo db) "record" "\n") (chk (database-field-sepinfo db) "field" "\t") (edb--1D! db :substitution-no-no (apply 'concat (mapcar (lambda (pair) (concat (car pair) (cdr pair))) (database-substitutions db)))))) (defmacro db-jam-si (afrag si) ;; AFRAG is a sepinfo accessor func name fragment (symbol). ;; SI is a variable (symbol) bound to a sepinfo. (let ((rx-acc (intern (format "sepinfo-%s-regexp" afrag))) (subrx-acc (intern (format "sepinfo-%s-regexp-submatch" afrag)))) `(let ((str (,(intern (format "sepinfo-%s-string" afrag)) ,si))) (cond ((or (null str) (equal "" str)) (setf (,rx-acc ,si) nil) (setf (,subrx-acc ,si) nil)) (t (setf (,rx-acc ,si) (regexp-quote str)) (setf (,subrx-acc ,si) 0)))))) (defun db-rfspec<-rftype (type) "Return the recordfieldspec associated with symbol TYPE." (let ((rv (gethash type (edb--G :1recordfieldtypes)))) (when rv (if (symbolp rv) (db-rfspec<-rftype rv) rv)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Substitution ;;; ;; When substitution is called, the rendered database is always in "simple" ;; format: rendered fields are separated by sub-fieldsep, and rendered records ;; (including the last one) are followed by sub-recordsep. ;; The "complicated" format includes pre-first-field at the beginning and ;; post-last-field (without record-sep-string or pre-first-field, which are ;; the other elements of sub-recordsep) at the end. ;; Simple format is nice because it requires no special-casing at the ;; beginning (because there's no gubbish there) or at the end (because ;; what's there is exactly what's between each pair of records). (defun database-perform-substitutions (db backward) (when (database-substitutions db) (db-message "Substituting...") ;; Make replacements in the current buffer according to SUBS. ;; SUBS is list of pairs of strings; the cdr of each pair will be ;; substituted for the car, in order, unless optional argument BACKWARD is ;; non-nil, in which case the car is substituted for the cdr and the ;; substitutions are done in reverse order. ;; ;; Warn if any of the ;; substituted-in strings already appears in the buffer; such a ;; situation would make substitution, then unsubstitution, not yield ;; a result identical to the original buffer, since all instances of ;; the substituted-in string will be assumed on the reverse ;; substitution to have been the result of replacing a ;; substituted-for string. ;; ;; fixme: do all checking before any substitutions are done. --ttn (let ((subs (database-substitutions db)) bef aft ambiguity ambiguities) (dolist (sub (if backward (mapcar (lambda (pair) (cons (cdr pair) (car pair))) (reverse subs)) subs)) (setq bef (car sub) aft (cdr sub)) (goto-char (point-min)) (when (search-forward aft nil t) (setq ambiguity sub) (goto-char (point-min))) (while (search-forward bef nil t) (replace-match aft nil t)) ;; Don't complain if we didn't actually do any substitution. (when ambiguity (unless (= (point) (point-min)) (push ambiguity ambiguities)) (setq ambiguity nil))) (when ambiguities (error "Ambiguities: %s" ambiguities))) (db-message "Substituting...done"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Substitution Utilities ;;; ;; A "confirmation tuple" -- aka "conftup" -- has the form: ;; [FIELDSEP-BAD-P RECORDSEP-BAD-P NO-OF-RECORDS] (defsubst db-conftup-bad-fsep (conftup) (aref conftup 0)) (defsubst db-conftup-bad-rsep (conftup) (aref conftup 1)) (defsubst db-conftup-reccount (conftup) (aref conftup 2)) (defun db-confirm-seps (fsep rsep nfields nrecords) ;; Return a conftup. ;; Assume that recordsep appears at the end of the database as well. ;; here "-m" means "matches" (let* ((fsep-m (progn (goto-char (point-min)) (db-how-many-string-overlapping fsep))) (rsep-m (progn (goto-char (point-min)) (db-how-many-string-overlapping rsep))) (goal-fsep-m (and nrecords (* nrecords (1- nfields)))) (goal-rsep-m nrecords)) (if (equal fsep rsep) (progn (if nrecords (if (= rsep-m (+ goal-rsep-m goal-fsep-m)) (vector nil nil nrecords) (vector t t nil)) ;; Remember that fsep = rsep when reading this code. (if (zerop (% rsep-m nfields)) (vector nil nil (/ rsep-m nfields)) (if (zerop (% (1+ rsep-m) nfields)) ;; Field separator at the end of data was misinterpreted ;; as a record separator, so no record separator was added. (progn (goto-char (point-max)) (insert rsep) (vector nil nil (/ (1+ rsep-m) nfields))) (vector t t (/ rsep-m nfields)))))) ;; fsep and rsep unequal; see if one is a substring of the other. ;; At least one of these must be zero. (let ((f-in-r (db-how-many-substring-overlapping fsep rsep)) (r-in-f (db-how-many-substring-overlapping rsep fsep))) (if nrecords (progn ;; At most one of these is nonzero, so cond is OK. (cond ((> f-in-r 0) (incf goal-fsep-m (* goal-rsep-m f-in-r))) ((> r-in-f 0) (incf goal-rsep-m (* goal-fsep-m r-in-f)))) (vector (not (= fsep-m goal-fsep-m)) (not (= rsep-m goal-rsep-m)) nrecords)) (incf nfields f-in-r) (let ((apparent-records (if (= 1 nfields) rsep-m (/ fsep-m (1- nfields))))) (setq goal-rsep-m (if (zerop apparent-records) 1 (* apparent-records (1+ (* r-in-f fsep-m))))) (vector (or ;; Wrong field count; some record has too many or few. (not (= fsep-m (* apparent-records (1- nfields)))) ;; too many fseps compared to rseps (< rsep-m goal-rsep-m)) ;; too many rseps compared to fseps (< goal-rsep-m rsep-m) apparent-records))))))) (defun database-acceptable-delimiter-p (db delimiter) ;; Return t iff no characters of DELIMITER appear in `:substitution-no-no'. (when delimiter (let ((result t) (idx 0) (len (length delimiter)) (no-no (edb--1D db :substitution-no-no))) (while (and result (< idx len)) (if (db-find-char (elt delimiter idx) no-no) (setq result nil) (incf idx))) result))) (defun database-generate-delimiter (db &optional checkp) (let ((fsep (or (database-sub-fieldsep-string db) (database-full-fieldsep-string db))) (rsep (or (database-sub-recordsep-string db) (database-full-recordsep-string db))) (string (make-string 1 0)) (c 0) rv) (while (and (< c 256) (not rv)) (aset string 0 c) (if (and (database-acceptable-delimiter-p db string) (not (and checkp (progn (goto-char (point-min)) (search-forward string nil t)))) (not (db-find-char c fsep)) (not (db-find-char c rsep))) (setq rv string) (incf c))) (or rv (error "I can't find an acceptable delimiter!")))) ;;; db-file-io.el ends here edb-1.31/lisp/db-format.el0000444000175000017500000021467211016250651013537 0ustar ttnttn;;; db-format.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Displaying and editing database records. ;;; Code: (require 'easymenu) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Variables ;;; ;; ;; Location in the format (current field info) ;; ;; All of these variables include "this-" in their names. (defsubst dbf-this-field-name (this-ds) (and this-ds (db-fname<-fno (edb--1ds-record-index this-ds) dbc-database))) (defsubst dbf-this-field-text () ;; The text actually in the buffer. (buffer-substring-no-properties (edb--S :fbeg) (dbf-this-field-end-pos))) (defsubst dbf-set-this-field-text (field-text) "Make the format display FIELD-TEXT in the current field." ;; Set the text actually in the buffer. (let ((beg (edb--S :fbeg))) (delete-region beg (dbf-this-field-end-pos)) (goto-char beg)) (insert field-text)) (defsubst dbf-this-field-modified-p () (buffer-modified-p)) (defsubst dbf-set-this-field-modified-p (arg) (set-buffer-modified-p arg)) (:edb1 :1moving-mark (make-marker)) ;; ;; The displayed record ;; ;;;###safe-file-local-variable (defvar dbf-set-this-record-modified-function nil "A function called when the current record is marked as modified. The function takes no arguments and its return value is ignored. It is called after `:original' is copied to `:under' and after `:utkmodp' is set to t.") (defsubst dbf-set-this-record-modified-p (arg) "Set the value of `:utkmodp' to ARG. If ARG is non-nil and `:utkmodp' is nil, also do the necessary record-copying and call `dbf-set-this-record-modified-function'." (let ((cur (edb--S :utkmodp))) (edb--S! :utkmodp arg) (cond ((and arg (not cur)) (db-copy-r2r (edb--S :original) (edb--S :under)) (edb--1run-hooks 'dbf-set-this-record-modified-function))))) (defsubst dbf-displayed-record () "Return the record currently displayed in this data display buffer. This is `:under' if `:utkmodp' is non-nil and `:original' otherwise." (if (edb--S :utkmodp) (edb--S :under) (edb--S :original))) (defvar dbf-redisplay-entire-record-p nil "T if the whole record needs to be redisplayed. This is often set by change functions.") ;; ;; Hooks ;; ;;; Minor mode hooks (defvar db-view-mode-hooks nil "Function or list of functions called when Database View mode is entered.") (defvar db-edit-mode-hooks nil "Function or list of functions called when Database Edit mode is entered.") ;;; Movement hooks ;;;###safe-file-local-variable (defvar dbf-before-display-record-function nil "A function called before a record is displayed. The function takes one argument, the record. This is a good place to put calls to `db-change-format'. Depending on your function's implementation, however, you may silently override any user calls to that function.") ;;;###safe-file-local-variable (defvar dbf-enter-field-hook nil "A function (of no arguments) called whenever a display field is entered.") ;;; Change hooks ;;;###safe-file-local-variable (defvar dbf-first-change-function nil "A function called the first time a record field is modified, or nil. The function takes the fieldname and the old and new values as arguments, and returns t if the record should be redisplayed.") ;;;###safe-file-local-variable (defvar dbf-every-change-function nil "A function called whenever a record field is modified, or nil. The function takes the fieldname and the old and new values as arguments, and returns t if the record should be redisplayed.") (defun dbf-set-change-function (fieldname function) "Set the change function for FIELDNAME to FUNCTION in the current database. FUNCTION takes the fieldname and the old and new values as arguments, and returns t if the record should be redisplayed." (aset (edb--S :change-functions) (gethash fieldname (edb--1D dbc-database :nm2no)) function)) ;;;###safe-file-local-variable (defvar dbf-after-record-change-function nil "Function called whenever changes to a record are recorded semi-permanently by `dbf-process-current-record-maybe'. For convenience, the function takes the record as an argument, which is guaranteed to be `:under'. Its return value is ignored.") ;; ;; The format ;; ;; Some variables local to the data display buffer don't need to be changed ;; when the display format changes. The ones appearing below do. ;;;###safe-file-local-variable (defvar dbf-format-name-spec-alist nil "Association list of format names and format specifiers. Each format name is an arbitrary string. A format specifier is a filename or format file specifier, which is a list of values for format variables. The user sets the format specifier to a filename, and after that format file has been read, EDB replaces the filename with a list of values for format variables, so that the file need not be read again.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Constants ;;; (defconst db-ds+opts-rx (concat "\\\\" "\\([[:alpha:]][[:alnum:]<>,=-]*\\)" ; 1 "\\(\\\\ \\)?")) ; 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Abstraction ;;; ;; ;; Displayspec ;; ;; Besides `record-index' all other information has to do with display only. (defstruct (edb--1ds (:type vector) :named (:constructor edb--make-1ds) (:copier edb--copy-1ds)) record-index ; zero-based backref ;; size and shape indent min-width max-width min-height ; default 1 max-height ; default 1 min-bytes max-bytes ;; other display info truncation-display-action padding-action actual->display display->actual ;; Is this where these belong? Well, it lets me not make a new displayspec ;; for them... match-actual->display match-display->actual ;; editing info truncation-editing-action (reachablep t)) (put 'edb--1ds 'kwidx ; poor man's defsetf --ttn (let ((idx 0)) (mapcar (lambda (ent) (cons (intern (format ":%s" (symbol-name (car ent)))) (incf idx))) (cdr (get 'edb--1ds 'cl-struct-slots))))) ;; ;; Optspecinfo ;; ;; An optspecinfo tells how to interpret optional parameters to a ;; display field specification. An optspecinfo is a three-element list of ;; * param-name: a string ;; * settor: function taking a displayspec and a value and setting a slot ;; * opt-param->value: a function converting the optional parameter (that ;; is, the string that follows the equal sign) into the actual value. (defconst db-optspec-list (mapcar (lambda (x) `(,(nth 0 x) ,(flet ((dset (frag) (let ((f (intern (format "edb--1ds-%s" frag)))) `(lambda (ds val) (setf (,f ds) val))))) ;; Settor-or-accessor is either a settor function, a ;; slotname, or a list of slotnames. In the latter two ;; cases, it's first converted into a settor. (let ((settor-or-accessor (nth 1 x))) (cond ((functionp settor-or-accessor) settor-or-accessor) ((symbolp settor-or-accessor) (dset settor-or-accessor)) (t `(lambda (displayspec value) ,@(mapcar (lambda (frag) `(,(dset frag) displayspec value)) settor-or-accessor)))))) ,(nth 2 x))) '(("indent" indent (lambda (x) t)) ("noindent" indent (lambda (x) nil)) ("width" (min-width max-width) db-string->number) ("min-width" min-width db-string->number) ("max-width" max-width db-string->number) ("length" (min-width max-width) db-string->number) ("min-length" min-width db-string->number) ("max-length" max-width db-string->number) ("height" (min-height max-height) db-string->number) ("min-height" min-height db-string->number) ("max-height" max-height db-string->number) ("bytes" (min-bytes max-bytes) db-string->number) ("min-bytes" min-bytes db-string->number) ("max-bytes" max-bytes db-string->number) ("trunc-display" truncation-display-action intern) ("truncation-display-action" truncation-display-action intern) ("padding-action" padding-action intern) ("right-justify" padding-action (lambda (x) 'db-pad-left)) ("actual->display" actual->display intern) ("a->d" actual->display intern) ("display->actual" display->actual intern) ("d->a" display->actual intern) ;; match-actual->display and match-display->actual, ;; fields 13 and 14 [??? --ttn] ("truncation-editing-action" truncation-editing-action intern) ("trunc-edit" truncation-editing-action intern) ("reachable" reachablep (lambda (x) t)) ("unreachable" reachablep (lambda (x) nil))))) (defun db-pad-left (min-width rep rep-length) (concat (make-string (- min-width rep-length) 32) rep)) (defun db-pad-right (min-width rep rep-length) (concat rep (make-string (- min-width rep-length) 32))) (defun db-callconvert (convert fieldtext &rest args) (let ((res (if convert (condition-case err ;; Try calling it with one arg. (funcall convert fieldtext) (wrong-number-of-arguments ;; Call it with all args. (apply convert fieldtext args)) (error ;; Otherwise resignal; "while t" makes this work ;; under the debugger (see, eg, the code for the ;; "error" function). (while t (signal (car err) (cdr err))))) fieldtext))) (if (= 3 (length args)) ;; display->actual res ;; actual->display (if (stringp res) res "")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Macros ;;; ;; If the user has deleted some of the leading spaces, they'll be restored. ;; Don't do anything about tabs, not even untabifying. (defun db-unindentify (text) (let ((amt (dbf-this-field-indent))) (if amt (replace-regexp-in-string (concat "\n" (db-space-maybe-rx amt)) "\n" text) text))) (defun db-space-maybe-rx (n) ;; Return a regexp matching N or fewer occurrences of the space character. ;; If N is nil, return the empty string, which is sometimes not a regexp you ;; want to search for by itself. (if n (if (> n ;; Emacs 19's regexp routines fix bugs in the Emacs 18 and Lucid ;; Emacs versions, but are sometimes much slower. For deeply ;; indented fields, this can result in very slow editing. We ;; disable some error-checking and correction for fields indented ;; more than 8 characters. 8) (make-string (or n 0) 32) (let ((result (make-string (* 2 n) 32))) (setq n (1- (* 2 n))) (while (> n 0) (aset result n ??) (decf n 2)) result)) "")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Mode selection ;;; (defvar database-view-mode-menu) ; fixme: document. --ttn (defvar database-edit-mode-menu) ; fixme: document. --ttn (defalias 'database-view-mode 'db-view-mode) ; for C-h m (defun db-view-mode (&optional arg) "Switch to Database View mode. With an argument, toggle between Database View and Database Edit modes." (interactive "P") (cond ((and arg (eq 'database-view-mode major-mode)) (db-edit-mode)) ;; If already in Database View mode, don't do anything. ((not (eq 'database-view-mode major-mode)) (dbf-process-field-maybe t) (setq major-mode 'database-view-mode mode-name "Database View") (use-local-map database-view-mode-map) (when (edb--rget '(:edb1 :bprops) (current-buffer)) ; hmmm (edb--S! :this-fidx nil) (edb--S! :this-ds nil)) (setq buffer-read-only t) (goto-char (point-min)) (dbf-set-this-field-modified-p nil) (easy-menu-remove database-edit-mode-menu) (easy-menu-add database-view-mode-menu) (edb--1run-hooks 'db-view-mode-hooks) (force-mode-line-update)))) (defalias 'database-edit-mode 'db-edit-mode) ; for C-h m (defun db-edit-mode (&optional arg) "Switch to Database Edit mode. With an argument, toggle between Database Edit and Database View modes." (cond ((not (db-data-display-buffer-p)) (error "Only call this in database mode.")) ((and arg (eq 'database-edit-mode major-mode)) (db-view-mode)) (t (setq major-mode 'database-edit-mode mode-name "Database Edit") (use-local-map database-edit-mode-map) (if (edb--1D dbc-database :modifiable-p) (setq buffer-read-only nil) (message "%s" (substitute-command-keys (concat "Database is not modifiable; " "change that with \\[db-toggle-modifiable-p]")))) (easy-menu-add database-edit-mode-menu) (easy-menu-remove database-view-mode-menu) (edb--1run-hooks 'db-edit-mode-hooks) (force-mode-line-update)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Movement in the format ;;; (defun db-parse-buffer-error (format-string &rest args) ;;(debug nil (apply 'format format-string args)) (db-emergency-restore-format) (db-message "%s; %s" "I was confused about where I was" "changes to the field might have been lost")) (defun db-next-line-or-field (arg) "Move to ARGth next line. If that would move out of the current field, move to the closest field, but not the current one, wrapping if necessary." (interactive "p") (let ((goal-column (current-column)) goal-line) ;; Determine goal line. (db-forward-line-wrapping arg) (db-jump-to-point) (setq goal-line (db-current-line)) ;; Move to proper column. (move-to-column goal-column) (db-jump-to-point) ;; Off goal line: move back and as near to the goal column as possible. (when (> (db-current-line) goal-line) (db-previous-field-internal 1) (goto-char (dbf-this-field-end-pos))))) (defun db-move-to-field-exact (arg) "Move to the ARGth field in the display. Ignores reachablep." (db-first-field-internal t) (db-next-field-internal arg t) (edb--1run-hooks 'dbf-enter-field-hook)) (defun db-next-field (arg) "Move to ARGth next reachable field, wrapping if necessary. When called interactively, ARG defaults to 1." (interactive "p") (dbf-process-field-maybe t) (goto-char (edb--S :fbeg)) (if (> arg 0) (db-next-field-internal arg) (db-previous-field-internal (- arg))) ;; We have just moved to a new field, which certainly isn't modified yet. (dbf-set-this-field-modified-p nil) (edb--1run-hooks 'dbf-enter-field-hook)) (defun db-next-field-internal (arg &optional exact) ;; Arg should be positive. Assumes point is at the beginning of the field. ;; If EXACT is non-nil, reachablep is ignored. (let* ((displayspecs (edb--S :displayspecs)) (iftxt (edb--S :iftxt)) (this-fidx (edb--S :this-fidx)) (shown (edb--S :shown)) (len (length displayspecs))) (while (> arg 0) (if (not (db-skip-string-forward (aref shown this-fidx))) (db-parse-buffer-error "Didn't find field %s text `%s'." this-fidx (aref shown this-fidx)) (edb--S! :this-fidx (incf this-fidx)) (decf arg) (when (= len this-fidx) (unless (db-skip-string-forward (aref iftxt len)) (db-parse-buffer-error "Didn't find trailing text `%s' after field %s." (aref iftxt len) (1- len))) (edb--S! :this-fidx (setq this-fidx 0)) (goto-char (point-min))) (unless (db-skip-string-forward (aref iftxt this-fidx)) (db-parse-buffer-error "Didn't find field separator `%s' before field %s." (aref iftxt this-fidx) this-fidx)) ;; Implement reachablep. ;; fixme: handle infinite loop. --ttn (unless (or exact (edb--1ds-reachablep (aref displayspecs this-fidx))) (incf arg)))) (edb--S! :this-ds (aref displayspecs this-fidx)) (edb--S! :fbeg (point))) (buffer-disable-undo) (buffer-enable-undo) (when (looking-at (regexp-quote (aref (edb--S :shown) (edb--S :this-fidx)))) (let ((end-of-match (match-end 0))) (set-marker (edb--S :fend) (if (= end-of-match (point-max)) nil (1+ end-of-match)) (current-buffer))))) (defun db-previous-line-or-field (arg) "Move to ARGth previous line. If that would move out of the current field, move to the closest field, but not the current one, wrapping if necessary." (interactive "p") (let ((goal-column (current-column)) (vacated-line (db-current-line)) this-line) (db-forward-line-wrapping (- arg)) (move-to-column goal-column) (db-jump-to-point) (setq this-line (db-current-line)) (when (= this-line vacated-line) ;; We moved to a line containing no field, so db-jump-to-point ;; put us in the field following point; ie, one on the line in ;; which we started. This is not the desired behavior. ;; Get to a line containing a field. (db-previous-field-internal 1) (goto-char (dbf-this-field-end-pos)) ;; Go to the correct column. (move-to-column goal-column) ;; Avoid getting dumped back into this field. (goto-char (min (point) (dbf-this-field-end-pos))) ;; And end up there. (db-jump-to-point)))) (defun db-previous-field (&optional arg) "Move to ARGth previous reachable field, wrapping if necessary. When called interactively, ARG defaults to 1." (interactive "p") (dbf-process-field-maybe t) (goto-char (edb--S :fbeg)) (if (> arg 0) (db-previous-field-internal arg) (db-next-field-internal (- arg))) (dbf-set-this-field-modified-p nil) (edb--1run-hooks 'dbf-enter-field-hook)) (defun db-previous-field-internal (arg) ;; Arg should be positive. Assume point is at the beginning of the field. ;; pb = previous inter-field-text beginning (let* ((displayspecs (edb--S :displayspecs)) (iftxt (edb--S :iftxt)) (this-fidx (edb--S :this-fidx)) (shown (edb--S :shown)) (len (length displayspecs)) (pb (marker-position (edb--S :fend)))) (if pb (decf pb)) (while (> arg 0) (unless (db-skip-string-backward (aref iftxt this-fidx)) (db-parse-buffer-error "Didn't find field separator `%s' before field %s." (aref iftxt this-fidx) this-fidx)) (setq pb (point)) (edb--S! :this-fidx (decf this-fidx)) (decf arg) (when (< this-fidx 0) (edb--S! :this-fidx (setq this-fidx (1- len))) (goto-char (point-max)) (if (db-skip-string-backward (aref iftxt len)) (setq pb (point)) (db-parse-buffer-error "Didn't find trailing text `%s' after field %s." (aref iftxt len) this-fidx))) (unless (db-skip-string-backward (aref shown this-fidx)) (db-parse-buffer-error "Didn't find field %s text `%s'." this-fidx (aref shown this-fidx))) ;; Implement reachablep. ;; fixme: handle infinite loop. --ttn (unless (edb--1ds-reachablep (aref displayspecs this-fidx)) (incf arg))) (edb--S! :this-ds (aref displayspecs this-fidx)) (edb--S! :fbeg (point)) (buffer-disable-undo) (buffer-enable-undo) (set-marker (edb--S :fend) (and pb (if (or (= 1 pb) (= (point-max) pb)) nil (1+ pb)))))) (defun db-first-field-internal (&optional exact) ;; Move to first field. Optional EXACT means ignore reachability. (if (edb--S :this-fidx) (dbf-process-field-maybe t) (db-edit-mode)) (edb--S! :this-fidx 0) ;; We need this even if field-index was nil, because someone might have ;; sneakily moved point. (In fact, this is called after point is moved ;; via mouse.) (goto-char (point-min)) (let ((iftxt (edb--S :iftxt)) (this-fidx (edb--S :this-fidx))) (unless (db-skip-string-forward (aref iftxt 0)) (db-parse-buffer-error "Didn't find field separator `%s' before field %s." (aref iftxt this-fidx) this-fidx)) (db-next-field-internal 0) ;; Implement reachablep. (unless (or exact (edb--1ds-reachablep (aref (edb--S :displayspecs) this-fidx))) (db-next-field-internal 1))) (dbf-set-this-field-modified-p nil)) (defun db-first-field () "Move to first field." (interactive) (db-first-field-internal nil) (edb--1run-hooks 'dbf-enter-field-hook)) (defun db-last-field () "Move to last field." (interactive) (db-first-field-internal nil) (db-previous-field 1)) (defun db-scroll-up () "Like scroll-up, but also edits the nearest database field." (interactive) (scroll-up) (db-jump-to-point t)) (defun db-scroll-down () "Like scroll-down, but also edits the nearest database field." (interactive) (scroll-down) (db-jump-to-point t)) (defun db-jump-to-point (&optional quietly) "In a data display buffer, move to the field containing or following point. In a summary buffer, move to the record displayed around point." (cond ((db-data-display-buffer-p) (let* ((this-fidx (edb--S :this-fidx)) (beg (and this-fidx (edb--S :fbeg)))) (unless (and beg (and (<= beg (point)) (<= (point) (dbf-this-field-end-pos)))) ;; moving outside current field. (let ((new-point (point))) (set-marker (edb--G :1moving-mark) (point)) ;; Go back to where we were: ;; if we were in a field, get back in it. (when this-fidx (goto-char beg)) (if (and this-fidx (> (marker-position (edb--G :1moving-mark)) (point))) ;; We are in a field and moving forward. (progn (dbf-process-field-maybe t) (goto-char beg)) (db-first-field-internal nil)) ;; If the dbf-process-field-maybe redisplays the entire record, ;; the marker gets wiped out (points to the beginning of the ;; buffer, because the buffer is cleared and refilled). (let ((moving-pos (marker-position (edb--G :1moving-mark)))) (unless (= 1 moving-pos) (setq new-point moving-pos))) (set-marker (edb--G :1moving-mark) nil) (let ((len (length (edb--S :displayspecs)))) (while (and (> new-point (dbf-this-field-end-pos)) (< (edb--S :this-fidx) (1- len))) ;; The EXACT argument is t so we don't infinite-loop when ;; the last field is unreachable. (db-next-field-internal 1 t))) (let ((this-ds (edb--S :this-ds))) (unless (edb--1ds-reachablep this-ds) ;; This message is getting wiped out by the ;; mouse-button-up event. How can I fix this? ;; Hint: Transposing the following two statements is ;; not the answer. (unless quietly (db-message "Field `%s' is unreachable" (db-fname<-fno (edb--1ds-record-index this-ds) dbc-database))) (db-next-field-internal 1))) (edb--1run-hooks 'dbf-enter-field-hook) ;; The max makes sure we're in a field, not beyond it. ;; The min is there only for the last field (because we could ;; be past it, in which case there's not a following field). (goto-char (min (max new-point (edb--S :fbeg)) (dbf-this-field-end-pos))))) ;; Check not in indentation even if didn't move to a new field. (when (let ((amt (dbf-this-field-indent))) (and amt (> amt 0) (db-looking-back-at "^ +") (< (current-column) amt))) (db-beginning-of-line-or-field)))) ((db-summary-buffer-p) ;; This is wrong in the presence of hidden directory lines. (beginning-of-line) (let* ((p (edb--S :point)) (lines (count-lines p (point))) (signed (if (< p (point)) lines (- lines)))) (goto-char p) (dbs-next-record-ignore-hiding (/ signed (edb--1D dbc-database :sum1lines))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Movement within a field ;;; ;; These shouldn't be called if not on a field, so they don't check. (defsubst dbf-this-field-end-pos () (let ((pos (marker-position (edb--S :fend)))) (if pos (1- pos) (point-max)))) (defun dbf-this-field-indent () (let ((in (edb--1ds-indent (edb--S :this-ds)))) (and in (if (numberp in) in (save-excursion (goto-char (edb--S :fbeg)) (current-column)))))) ;;; ;;; Checking ;;; (defalias 'dbf-inform-outside-field ;; Function to call when point attempts to leave a field. ;; It should take one argument, a short message string. 'error) (defsubst dbf-check-if-outside-field (&optional quietly) ;; Move point to beginning of field if it's before that. (let ((beg-pos (edb--S :fbeg))) (when (< (point) beg-pos) (goto-char beg-pos) (unless quietly (db-message "Beginning of field")))) ;; Move point to end of field if it's beyond that. (let ((end-pos (dbf-this-field-end-pos))) (when (> (point) end-pos) (goto-char end-pos) (unless quietly (dbf-inform-outside-field "End of field."))))) ;;; ;;; Movement ;;; (defsubst db-beginning-of-field () "Move to the beginning of the current field." (interactive) (goto-char (edb--S :fbeg))) (defsubst db-end-of-field () "Move to the end of the current field." (interactive) (goto-char (dbf-this-field-end-pos))) (defun db-beginning-of-line-or-field () "Move to the beginning of the current line of the current field. If invoked twice in succession, move to beginning of field." (interactive) (if (eq 'db-beginning-of-line-or-field last-command) (db-beginning-of-field) (beginning-of-line) (db-skip-regexp-forward (db-space-maybe-rx (dbf-this-field-indent))) (dbf-check-if-outside-field t))) (defun db-end-of-line-or-field (arg) "Move to the end of the current line of the current field. If invoked twice in succession, move to end of field." (interactive "p") (if (eq 'db-end-of-line-or-field last-command) (db-end-of-field) (end-of-line arg) (dbf-check-if-outside-field t))) (defun db-forward-char (arg) "Like forward-char, but won't go outside field." (interactive "p") (if (< arg 0) (db-backward-char (- arg)) (let ((indent (dbf-this-field-indent))) (while (> arg 0) (if (eobp) ;; This is so we get the error "End of field" ;; instead of "End of buffer". (progn (setq arg 0) (dbf-inform-outside-field "End of field.")) (forward-char 1) (db-skip-regexp-forward (concat "^" (db-space-maybe-rx indent))) (decf arg))) (dbf-check-if-outside-field)))) (defun db-backward-char (arg) "Like backward-char, but won't go outside field." (interactive "p") (if (< arg 0) (db-forward-char (- arg)) (let ((indent (dbf-this-field-indent))) (while (> arg 0) (if (bobp) ;; This is so we get the error "Beginning of field" ;; instead of "Beginning of buffer". (progn (setq arg 0) (dbf-inform-outside-field "Beginning of field.")) (let ((rx (concat "^" (db-space-maybe-rx indent))) (here (point))) (when (re-search-backward rx nil t) (if (= here (match-end 0)) t (goto-char here) nil))) (backward-char 1) (decf arg))) (dbf-check-if-outside-field)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Editing ;;; (defun db-delete-char (arg) (interactive "p") "Like delete-char, but won't delete outside the field." (delete-region (point) (progn (db-forward-char arg) (point)))) (defun db-backward-delete-char (arg) (interactive "p") "Like delete-backward-char, but won't delete outside the field." (delete-region (point) (progn (db-backward-char arg) (point)))) (defun db-forward-word (arg) "Like forward-word, but won't go outside field." (interactive "p") (forward-word arg) (dbf-check-if-outside-field)) (defun db-backward-word (arg) "Like backward-word, but won't go outside field." (interactive "p") (db-forward-word (- arg))) (defun db-copy-region-as-kill (beg end) "Save the region as if killed, but don't kill it." (interactive "r") (let ((text (db-unindentify (buffer-substring beg end)))) (if (eq last-command 'db-kill-region) (kill-append text (< end beg)) (push text kill-ring) (when (> (length kill-ring) kill-ring-max) (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))) (setq this-command 'db-kill-region) (setq kill-ring-yank-pointer kill-ring)) (defun db-kill-region (beg end) "Kill between point and mark. The text is deleted but saved in the kill ring. See `kill-region' for details." (interactive "*r") (db-copy-region-as-kill beg end) (delete-region beg end)) (defun db-kill-word (arg) "Like kill-word, but won't delete outside the field." (interactive "p") (db-kill-region (point) (progn (db-forward-word arg) (point)))) (defun db-backward-kill-word (arg) "Like backward-kill-word, but won't delete outside the field." (interactive "p") (db-kill-word (- arg))) (defun db-kill-line (arg) "Like kill-line, but won't delete outside the field." (interactive "p") (let ((here (point))) (db-end-of-line-or-field arg) (when (< (point) (dbf-this-field-end-pos)) (let ((indent (dbf-this-field-indent))) (cond (kill-whole-line (db-skip-regexp-forward (concat "[ \t]*\n" (db-space-maybe-rx indent)))) ((and (eolp) (= indent (current-column))) (forward-char (1+ indent)))))) (db-kill-region here (point)))) (defun db-kill-to-end () "Kill from point to the end of the current field." (interactive) (db-kill-region (point) (dbf-this-field-end-pos))) (defun db-newline (arg) "Insert a newline. Will not make the current field too tall. If current field's maximum height is 1 line, move to the next field instead." (interactive "p") ;; ignores the argument (let ((max-h (edb--1ds-max-height (edb--S :this-ds)))) (if (or (not max-h) (< (count-lines (edb--S :fbeg) (dbf-this-field-end-pos)) max-h)) (let ((indent (dbf-this-field-indent))) (newline 1) (when indent (insert (make-string indent 32)))) (if (= 1 max-h) (db-next-field 1) (db-message "Field is at maximum height already"))))) (defun db-open-line (arg) "Insert a newline and leave point before it. Will not make the current field too tall." (interactive "p") (let ((here (point))) (db-newline arg) (goto-char here))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Value processing for fields and records ;;; (defun dbf-process-field-maybe (set-text-p) ;; Set the value of the current record from the current field. ;; If arg SET-TEXT-P is non-nil, update the display as well. ;; Return t if field is unmodified or text is OK; nil otherwise. ;; May move point. (let ((fno (and (edb--rget '(:edb1 :bprops) (current-buffer)) (edb--S :this-fidx))) (shown (edb--S :shown))) (cond ((not fno)) ((not (dbf-this-field-modified-p))) ((or (< (point) (edb--S :fbeg)) (> (point) (dbf-this-field-end-pos))) (db-parse-buffer-error "Point was outside (%d) of current field (%d - %d)." (point) (edb--S :fbeg) (dbf-this-field-end-pos)) ;; Return something in case `db-parse-buffer-error' returns. ;; TODO: Is this the right return value? --ttn nil) ((equal (dbf-this-field-text) (aref shown fno)) ;; Field is unchanged, so mark it unmodified. (dbf-set-this-field-modified-p nil)) (t ;; Field has been modified. (let* ((this-ds (edb--S :this-ds)) (this-fname (dbf-this-field-name this-ds)) (cur (db-callconvert (edb--1ds-display->actual this-ds) (let ((text (dbf-this-field-text))) (db-unindentify text)) (aref (dbf-displayed-record) fno) (dbf-displayed-record) fno)) (idx (edb--1ds-record-index this-ds)) (old (aref (dbf-displayed-record) idx)) (under (edb--S :under)) (saved-modified-p (edb--S :utkmodp))) (unless (equal cur old) ;; The new value is different from the old. (dbf-set-this-record-modified-p t) (db-check-constraint cur under idx dbc-database) (aset under idx cur) (when set-text-p (aset shown fno (let ((pr (db-ds-printed this-ds under)) (in (edb--1ds-indent this-ds))) (if in (if (numberp in) (replace-regexp-in-string "\n" (concat "\n" (make-string in 32)) pr) ;; Why can't I use (dbf-this-field-indent) even here? (if (db-find-char ?\n pr) (error "Don't know how much to indent.") pr)) pr)))) ;; No need to do redisplay before the change-hooks are ;; called since the user's version is already onscreen ;; and that will be very similar indeed to the display ;; text. (unless saved-modified-p (setq dbf-redisplay-entire-record-p (or (and dbf-first-change-function (funcall dbf-first-change-function this-fname old cur)) dbf-redisplay-entire-record-p))) (setq dbf-redisplay-entire-record-p (or (and dbf-every-change-function (funcall dbf-every-change-function this-fname old cur)) dbf-redisplay-entire-record-p)) (setq dbf-redisplay-entire-record-p (let ((change-function (aref (edb--S :change-functions) idx))) (or (and change-function (funcall change-function this-fname old cur)) dbf-redisplay-entire-record-p)))) ;; The text is different; the value may or may not have differed. ;; Display the standard representation for this value, which has ;; already been computed. (when set-text-p (unless (dbf-redisplay-entire-record-maybe) ;; set-field-text always returns nil (dbf-set-this-field-text (aref shown fno)))) (dbf-set-this-field-modified-p t)))))) (defun dbf-redisplay-entire-record-maybe () ;; If `dbf-redisplay-entire-record-p' is non-nil, redisplay current record ;; and return t; otherwise return nil. (when dbf-redisplay-entire-record-p (setq dbf-redisplay-entire-record-p nil) (db-emergency-restore-format t) t)) (defun dbf-process-current-record-maybe (set-text-p) ;; Commit changes to the record being displayed and edited. If the current ;; record (see `dbf-displayed-record') is a modified copy of a database ;; record, this copies it back to the original database record, modifying ;; the database by side effect. Return t if successful, nil otherwise. ;; SET-TEXT-P non-nil means to also update the display. (when (edb--S :index) ;; Sets the field unmodified, if appropriate (dbf-process-field-maybe set-text-p) (when (edb--S :utkmodp) ;; Do any programmer-requested checking or postprocessing here. ;; This function may err, aborting out of whatever was trying to ;; process the current record and do something else. (edb--1run-hook-with-arg 'dbf-after-record-change-function (dbf-displayed-record)) (db-copy-r2r (edb--S :under) (edb--S :original)) (dbf-update-summary-item (edb--S :index)) ;; what about hiddenp and markedp? --ttn (database-set-modified-p dbc-database t) (edb--S! :utkmodp nil) (dbf-set-this-field-modified-p nil)) ;; This function shouldn't have been called on a non-database record; how ;; did we get here? It may not be the case that the info is about to be ;; abandoned. (or (not (edb--S :utkmodp)) (y-or-n-p "Abandon the displayed information? ") (error "Don't abandon displayed information.")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Undoing changes ;;; (defun db-revert-field (&optional quietly) "Undo any changes made since entering this field. Replace the onscreen text in this field with that of the underlying record. A similar effect can be had by invoking \\[advertised-undo] multiple times." (interactive) (let ((fname (unless quietly (dbf-this-field-name (edb--S :this-ds))))) (if (dbf-this-field-modified-p) (progn (dbf-set-this-field-text (aref (edb--S :shown) (edb--S :this-fidx))) (dbf-set-this-field-modified-p nil) (unless quietly (db-message "Reverted field `%s'" fname))) (unless quietly (db-message "Can't revert field `%s'; no changes since moving onto it" fname))))) (defun db-revert-record () "Set the record to be the same as the corresponding one in the database. In other words, undo any changes made since entering this record." (interactive) (db-revert-field t) (if (edb--S :utkmodp) (let ((buffer-read-only nil)) (edb--S! :utkmodp nil) (db-display-record (dbf-displayed-record) t) (let ((this-fidx (edb--S :this-fidx))) (when this-fidx (db-move-to-field-exact this-fidx))) (db-message "Reverted record")) (db-message "Can't revert this record; no changes since selecting it"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Set displayspec from string ;;; (defun db-dspec<-dtype (type) "Return a copy of the displayspec corresponding to string or symbol TYPE. Return nil if there's no corresponding displayspec." (let ((ds (gethash (if (stringp type) (intern type) type) (edb--G :1displaytypes)))) (when ds (if (symbolp ds) (db-dspec<-dtype ds) (edb--copy-1ds ds))))) (defun db-dspec<-string (s db) ;; Assume match-data from `db-ds+opts-rx'. S is nil if from the buffer. (let* ((ls (split-string (match-string 1 s) ",")) (fname (intern (car ls))) (fidx (and db (gethash fname (edb--1D db :nm2no)))) (type (and fidx (aref (db-rs-slice db 'edb--1rs-type) fidx))) ds) (when (and db (not fidx)) (error "%s is not a field or field abbreviation." fname)) (setq ds (db-dspec<-type/opts type (cdr ls))) (unless ds (error "Type %s in field %d (%s) not recognized." type fname fidx)) (setf (edb--1ds-record-index ds) fidx) ds)) (defun db-dspec<-type/opts (type opts &optional notype-ok) ;; Either TYPE or OPTS (list of strings) must specify a type, unless ;; optional argument NOTYPE-OK is specified, in which case an empty ;; displayspec may be returned. ;; Ordinarily (for instance, when this is being called to parse part of a ;; format), NOTYPE-OK should not be specified, so that invalid ;; displaytypes aren't created. ;; A type in OPTS overrides TYPE. (if (not (setq opts (delete "" opts))) (if type (or (db-dspec<-dtype type) (error "No such displaytype as `%s'." type)) (edb--make-1ds)) (let (ds) ;; set the displayspec ;; note tricky sequencing (if (setq ds (db-dspec<-dtype (intern (car opts)))) (pop opts) (if type (setq ds (db-dspec<-dtype type)) (error "No type specified in `%s'." opts))) (while opts (let* ((pair (split-string (pop opts) "=")) (opt (car pair)) (val (or (cadr pair) "")) (spec (or (assoc opt db-optspec-list) (error "Invalid optional field spec name or type: %s" opt)))) (funcall (nth 1 spec) ds (funcall (nth 2 spec) val)))) ds))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Read a format file ;;; (defun db-setup-data-display-buffer (template db new-p) ;; Create and return a data display buffer. This is only called when a ;; brand-new data display buffer is being created, not when one is being ;; refreshed. Arguments are TEMPLATE DB NEW-P. TEMPLATE may either be ;; a buffer containing a display format, or the name of a format file. ;; If NEW-P is non-nil, then the database's auxiliary file is read and ;; its field variables are set. ;; ;; WARNING: If the format file's local variables set particular database ;; slots (such as fieldnames), and NEW-P is nil, then the database may be ;; left in an inconsistent state. The "primary" format, which is read in ;; before the database is, should perform any such neccessary actions. (unless (bufferp template) (setq template (expand-file-name template)) (unless (file-readable-p template) (error "Can't read format file `%s'." template))) (with-current-buffer (db-make-data-display-buffer db new-p) (assert (eq dbc-database db) t) (setq buffer-read-only nil) ; (database-mode) set it to t (funcall (cond ((bufferp template) 'insert-buffer-substring) (t 'insert-file-contents)) template) (edb--S! :format-file (if (bufferp template) "(internal)" template)) (when (and new-p (not (equal "(internal)" (edb--S :format-file)))) (let ((aux (db-locate-readable-file-prefer-cwd (file-name-sans-extension (edb--1D db :file)) (cons default-directory db-aux-file-path) db-aux-file-suffixes))) (when aux ;; Note that the variable `database' is dynamically bound. (let ((database db)) (load-file aux))))) ;; Note that the variable `database' is dynamically bound. (let ((database db)) (db-really-hack-local-variables)) ;; This is the second half of `insert-buffer-substring-no-properties' ;; that we used to use. Unfortunately, we need the properties to be ;; around during local variables processing (ugh). (let ((inhibit-read-only t)) (set-text-properties (point-min) (point-max) nil)) ;; Initialize local variables. ;; Assume `dbc-database' already set. (let ((nfields (length (database-fieldnames dbc-database)))) (unless (< 0 nfields) (error "Can't tell how many fields database has.")) (edb--S! :change-functions (make-vector nfields nil)) (edb--S! :under (make-vector nfields nil)) (when new-p ;; Initialize database variables. We didn't do this earlier because ;; they may depend on some values set in the format file. (unless (edb--1D db :togp) ;; Do this before the format is parsed but after the format's local ;; variables have been hacked. (unless (database-field-priorities db) (setf (database-field-priorities db) (list (mapcar 'list (number-sequence 0 (1- nfields))))))))) (db-setup-ddb-parse-displayspecs db) (setq buffer-read-only t) (current-buffer))) (defun db-make-data-display-buffer (db new-p) ;; Create and return a data display buffer; set some vars. (with-current-buffer (create-file-buffer (edb--1D db :file)) (set (make-local-variable 'edb--bprops) (edb--rinit '(:edb1 :bprops) (current-buffer) :size 23 :test 'eq :weakness 'key)) (edb--S! :fend (make-marker)) (edb--S! :wraparound 'delay) (edb--S! :stay-in-edit-mode-p t) (let ((dir (file-name-directory (edb--1D db :file)))) (when dir (setq default-directory (expand-file-name dir)))) (set (make-local-variable 'dbc-database) db) (dolist (var '(db-new-record-function dbf-set-this-record-modified-function dbf-redisplay-entire-record-p dbf-before-display-record-function dbf-enter-field-hook dbf-first-change-function dbf-every-change-function dbf-after-record-change-function dbf-format-name-spec-alist)) (set (make-local-variable var) nil)) (unless new-p ;; These are per-data-display-buffer variables. (let ((nfields (length (database-fieldnames db)))) (edb--S! :change-functions (make-vector nfields nil)) (edb--S! :under (make-vector nfields nil)))) (database-mode) (current-buffer))) (defun db-setup-ddb-parse-displayspecs (db) ;; Get rid of local variables. (goto-char (point-max)) (search-backward "\n\^L" (point-min) 'move) (when (search-forward (concat "Local" ; use `concat' to avoid " " ; misinterpretation "Variables:") nil t) (beginning-of-line 1) (delete-region (point) (point-max))) ;; Get rid of whitespace at end of buffer. (goto-char (point-max)) (re-search-backward "[^ \t\n]") (delete-region (match-end 0) (point-max)) ;; Get rid of whitespace at ends of lines. (goto-char (point-min)) (while (re-search-forward "[ \t]+$" nil t) (delete-region (match-beginning 0) (match-end 0))) (let ((prev-end (point-min)) (backslash-placeholder (and (goto-char (point-min)) (search-forward "\\\\" nil t) ;; assume this doesn't return nil (db-unused-char-in-buffer))) len beginning end ds ds-ls ift-ls) ; inter-field-text (when backslash-placeholder (setq backslash-placeholder (char-to-string backslash-placeholder)) (goto-char (point-min)) (while (search-forward "\\\\" nil t) (replace-match backslash-placeholder nil t))) (edb--S! :default-sumfmt nil) (goto-char (point-min)) (while (re-search-forward db-ds+opts-rx nil t) (setq beginning (match-beginning 0) end (match-end 0) ;; Call "internal" version of function because match-data is set. ;; nil as first argument means make it from the buffer. ds (db-dspec<-string nil db)) ;; Fix up backslash-replacement. The buffer is fixed up instead of ;; just the ift-ls because of the call to current-column. (when backslash-placeholder (save-excursion (save-restriction (narrow-to-region prev-end beginning) (goto-char prev-end) (while (search-forward backslash-placeholder nil t) (replace-match "\\" nil t))))) (push (buffer-substring prev-end beginning) ift-ls) ;; Match about to be deleted; we just used the old value. (setq prev-end beginning) (unless (edb--S :default-sumfmt) (edb--S! :default-sumfmt (save-excursion (buffer-substring (progn (beginning-of-line 1) (point)) (progn (end-of-line 1) (point))))) (unless (edb--S :sumfmt) (edb--S! :sumfmt (edb--S :default-sumfmt)))) (delete-region beginning end) (when (eq t (edb--1ds-indent ds)) (setf (edb--1ds-indent ds) (current-column))) (push ds ds-ls)) ;; Fix up backslash-replacement for the post-last text. (when backslash-placeholder (save-excursion (save-restriction (narrow-to-region prev-end (point-max)) (goto-char prev-end) (while (search-forward backslash-placeholder nil t) (replace-match "\\" nil t))))) (push (buffer-substring prev-end (point-max)) ift-ls) (edb--S! :iftxt (vconcat (nreverse ift-ls))) (edb--S! :displayspecs (vconcat (nreverse ds-ls))) (setq len (length (edb--S :displayspecs))) ;; The vector for :search-defaults is one element longer than the number ;; of fields; last element is the default for a search over all fields. (edb--S! :search-defaults (make-vector (1+ len) nil)) (edb--S! :shown (make-vector len nil))) ;; Initialize more local variables. (edb--S! :fidx2dsidx (make-vector (length (database-fieldnames db)) nil)) (let ((all-ds (edb--S :displayspecs)) (fidx2dsidx (edb--S :fidx2dsidx))) (dotimes (fsno (length all-ds)) (aset fidx2dsidx (edb--1ds-record-index (aref all-ds fsno)) fsno))) (dbf-set-summary-format (or (edb--S :sumfmt) (mapconcat (lambda (sym) (format "\\%s" sym)) (append (database-fieldnames db) nil) " "))) (set-buffer-modified-p nil)) (defun db-additional-data-display-buffer () "Create another data display buffer in which to view this database." (interactive) (dbf-process-current-record-maybe t) (let* ((cur (current-buffer)) (database dbc-database) (new (db-make-data-display-buffer database nil))) (let ((ddbufs (edb--1D database :ddbufs))) (edb--1D! database :ddbufs (cons new ddbufs))) (switch-to-buffer-other-window new) (db-copy-buffer-local-variables cur) (edb--rput '(:edb1 :bprops) (current-buffer) (copy-hash-table (edb--rget '(:edb1 :bprops) cur))) (edb--S! :sumbuf nil) ;; Here are the trampled-on variables that we really cared about. (edb--S! :under (make-vector (length (edb--S :original)) nil)) (db-emergency-restore-format t))) (defun db-change-format (&optional format-name filename) "Select and use an alternate display format to view the database. If neither FORMAT-NAME nor FILENAME is specified (as is the case when this is called interactively), the user is prompted for them. In Emacs Lisp code, if `dbf-format-name-spec-alist' has been been set, usually only one of the arguments is specified. If both are specified, then FORMAT-NAME becomes a name for the format FILENAME specifies; if FORMAT-NAME is already associated with a different format file, an error is signalled. If the current format is unnamed, the user is prompted for a name to give it, so that it can be conveniently restored if need be. This behavior is suppressed, and the record is not displayed, if the function is not being called interactively. The data display buffer is left in Database View mode. Selecting the current format does not cause any work to be done. Some databases automatically set the format of the record being displayed, usually by setting `dbf-before-display-record-function' to a function that overrides the format in effect when a record is about to be displayed. This may cause this function to appear not to be doing any work. In actuality the format is being set, then reset." (interactive) (unless (and format-name (equal format-name (edb--S :format-name))) ;; We're not already in the requested format (db-view-mode) ;; If neither format- nor filename is specified, query for one of them. (unless (or format-name filename) (setq format-name (completing-read "Use which format? (? for options, RET to specify a file) " (cons '("") dbf-format-name-spec-alist) (lambda (elem) (stringp (car elem))) t)) (when (equal "" format-name) (setq format-name nil filename (read-file-name "File for new format: " nil nil t)))) ;; Either `format-name' or `filename' -- or possibly both, ;; if not called interactively -- is set. (when filename (setq filename (db-locate-format-file filename))) (when format-name (let ((file-name-handler-alist (cons (cons "^(connection)" 'edb--connection-file-cache) file-name-handler-alist)) (spec (cdr (assoc format-name dbf-format-name-spec-alist)))) (if spec ;; successful format-name (let ((fs-filename (if (listp spec) (car spec) spec))) (if filename (when (and fs-filename ;; This test is required for interactive ;; uses of `db-change-format'. (not (db-same-file-p filename fs-filename))) (error "Format name %s is associated with %s, not %s." format-name fs-filename filename)) (setq filename (db-locate-format-file fs-filename)))) ;; unsuccessful format-name (if filename (push (cons format-name filename) dbf-format-name-spec-alist) ;; no filename, failed format-name (error "`%s' is not the name of a format." format-name))))) ;; Filename is now set. (flet ((mkspec (sumfmt sumfun) ;; All of these items vary from format to format within a ;; particular data display buffer. (list (edb--S :format-file) ;; These can vary between data display buffers which ;; happen to be using the same format file to specify the ;; layout of the record's fields. That is, these are ;; specific to a particular data display buffer, not to a ;; format, because they have to do with what is actually ;; being displayed and/or because we might expect the user ;; to change them after reading in the format. This is ;; why we can't just associate this information with the ;; format file, but have to save it on a ;; per-data-display-buffer basis. sumfmt sumfun (edb--S :shown) (edb--S :search-defaults)))) ;; First save away current format. ;; No need to do anything with filename. (let ((curname (edb--S :format-name))) (when (and (interactive-p) (not curname) (y-or-n-p "Give the current format a name? ")) (setq curname (read-string "Name for current format: ")) (edb--S! :format-name curname)) (when curname (let ((look (assoc curname dbf-format-name-spec-alist)) (spec (mkspec (edb--S :sumfmt) (edb--S :sumfun)))) (if look (setcdr look spec) (push (cons curname spec) dbf-format-name-spec-alist))))) ;; Now install the new format. (let ((prev-format-file (edb--S :format-file)) (fs (cdr (assoc filename (edb--S :fmtspec-stash))))) (edb--S! :format-name format-name) (edb--S! :format-file filename) (if fs (progn (mapc 'eval (edb--S! :always-forms (pop fs))) (edb--S! :displayspecs (pop fs)) (edb--S! :iftxt (pop fs)) (edb--S! :fidx2dsidx (car fs)) (let ((spec (cdr (assoc (or (edb--S :format-name) (intern (edb--S :format-file))) dbf-format-name-spec-alist)))) (edb--S! :format-file (pop spec)) (edb--S! :sumfmt (pop spec)) (edb--S! :sumfun (pop spec)) (edb--S! :shown (pop spec)) (edb--S! :search-defaults (car spec)))) ;; We didn't find `:format-file' in `:fmtspec-stash'; we probably ;; didn't find more than just a filename at `:format-name' in ;; dbf-format-name-spec-alist either. ;; This `let' is for the benefit of the new format file. (let ((file-name-handler-alist (cons (cons "^(connection)" 'edb--connection-file-cache) file-name-handler-alist)) (database dbc-database) (buffer-read-only nil)) ;; Though we shamefully cover up the fact that the original format ;; file is being re-read (this time for caching purposes), this at ;; least allows us to no longer suggest setting the format name in ;; the format file. All part of EDB 1.x janitorial services... ;; Also, don't mention anything for connection-bundled formats. (unless (or (memq (aref (edb--S :format-file) 0) '(?( ?))) (equal prev-format-file (edb--S :format-file))) (db-message "Reading format from file: %s" (edb--S :format-file))) (buffer-disable-undo) (erase-buffer) (insert-file-contents (edb--S :format-file)) (db-really-hack-local-variables) (db-setup-ddb-parse-displayspecs dbc-database) ;; Save away the file-invariant stuff. (edb--S! :fmtspec-stash (cons (list (edb--S :format-file) (edb--S :always-forms) (edb--S :displayspecs) (edb--S :iftxt) (edb--S :fidx2dsidx)) (edb--S :fmtspec-stash))) ;; Install the defaults under a symbol associated with the format ;; file (so it's not user-accessible). (push (cons (intern (edb--S :format-file)) (mkspec (edb--S :default-sumfmt) (when (equal (edb--S :sumfmt) (edb--S :default-sumfmt)) (edb--S :sumfun)))) dbf-format-name-spec-alist) (erase-buffer)))) (when (interactive-p) (db-display-record (dbf-displayed-record) t))))) (defun db-emergency-restore-format (&optional recompute) "Throw away the contents of the format buffer; redisplay the current record. Use this if the format gets munged. Changes made to the current field since last moving onto it may be lost. If optional argument RECOMPUTE is non-nil, the displayed text is recomputed as well." (db-display-record (dbf-displayed-record) recompute) (let ((this-fidx (edb--S :this-fidx))) (when this-fidx (dbf-set-this-field-modified-p nil) (db-move-to-field-exact this-fidx) ;; If the hook changed formats, we'll be in Database View mode. (db-edit-mode)))) (defun dbf-set-summary-format (summary-format) "Specify the format used in the Database Summary buffer. Argument SUMMARY-FORMAT is a string containing display specifications. Call this in the data display buffer, or in a format file or auxiliary file." (interactive (list (let ((sumfmt (edb--S :sumfmt))) (read-string "Summary format: " (cons sumfmt 0) nil sumfmt)))) (unless (stringp summary-format) (error "Argument to dbf-set-summary-format should be a string, not %s" summary-format)) (when (= ?\n (elt summary-format (1- (length summary-format)))) (setq summary-format (substring summary-format 0 -1))) (edb--S! :sumfmt summary-format) (dbf-set-summary-out-of-date-p) (when (edb--S :sumbuf) (with-current-buffer (edb--S :sumbuf) (let ((ht (edb--S :summaries))) (when ht (clrhash ht))))) (let ((lasfl (db-format->lines/sforms summary-format dbc-database 2 t nil))) ;; The (constant) number of screen lines occupied by each record summary, ;; computed automatically from the summary format. This doesn't depend ;; on the field values in the individual records because ;; db-format->lines/sforms errs if min-height is not equal to max-height ;; (unless variable-height is set). That makes determining which summary ;; point is in, and getting to a particular summary, much easier. (edb--1D! dbc-database :sum1lines (car lasfl)) (edb--S! :sumfun `(lambda (formatted-record) (concat ,@(cdr lasfl)))))) (defmacro dbf-always (&rest body) "Execute forms in BODY, and arrange to execute them in the future each time that this format replaces another." (declare (debug body)) `(progn (edb--S! :always-forms (nconc (edb--S :always-forms) ,body)) ,@body)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Display data in a format ;;; (defvar db-display-record-redo-inter-field-text-function nil "Function taking two args called in two contexts during `db-display-record'. The args are BUF and EXTENTS-LIST. In the first call, done right before erasing the buffer, EXTENTS-LIST is null. In the second call, done after text has been inserted in the buffer and point is at point-min, EXTENTS-LIST is a list of pairs of buffer positions in BUF that define the \"inter-field text\", that is the text specifically not representing the data, but instead part of the display format.") (defun db-display-record (record &optional recompute fieldno-limit) ;; Why take RECORD argument instead of using var `dbf-displayed-record'? ;; Joe Wells has used this feature, so don't remove it. "Display RECORD in the current buffer, which is a data display buffer. If optional arg RECOMPUTE is non-nil, the display representations will be computed first; RECOMPUTE is typically non-nil only the first time a record is shown. If optional third arg FIELDNO-LIMIT is non-nil, only fieldnumbers strictly less than it will be displayed." (let* ((buffer-read-only nil) (is-displayed-record-p (eq record (dbf-displayed-record))) ;; If quitting occurs in the middle of this operation, EDB becomes ;; very confused. WARNING: Inhibitting quitting is dangerous. (inhibit-quit t) displayspecs shown len iftxt ds rep ext-start ift-extents) (run-hook-with-args 'dbf-before-display-record-function record) ;; Do after in case `dbf-before-display-record-function' changes things. (setq displayspecs (edb--S :displayspecs) shown (edb--S :shown) len (length displayspecs) iftxt (edb--S :iftxt)) ;; Allow dbf-before-display-record-function to do ;; dbf-set-this-record-modified-p if it wants to. (when is-displayed-record-p (setq record (dbf-displayed-record))) (buffer-disable-undo) (run-hook-with-args 'db-display-record-redo-inter-field-text-function (current-buffer) nil) (erase-buffer) (dotimes (fidx len) (setq ds (aref displayspecs fidx)) (setq ext-start (point)) (insert (aref iftxt fidx)) (push (cons ext-start (point)) ift-extents) (when recompute (aset shown fidx (if (and fieldno-limit (>= fidx fieldno-limit)) ;; fixme: handle min-height and min-bytes. --ttn (make-string (or (edb--1ds-min-width ds) 0) 32) (setq rep (db-ds-printed ds record)) (replace-regexp-in-string "\n" (concat "\n" (make-string (current-column) 32)) rep)))) (insert (aref shown fidx))) (setq ext-start (point)) (insert (aref iftxt len)) (push (cons ext-start (point)) ift-extents) (dbf-set-this-field-modified-p nil) ;; This place is as good as any for leaving the cursor by default. (goto-char (point-min)) (buffer-enable-undo (current-buffer)) (run-hook-with-args 'db-display-record-redo-inter-field-text-function (current-buffer) (nreverse ift-extents)) ;; If quitting occurred while this was happening, ignore it. (setq quit-flag nil))) (defun db-ds-printed (ds record) (let* ((ridx (edb--1ds-record-index ds)) (rep (db-callconvert (edb--1ds-actual->display ds) (aref record ridx) record ridx))) (let ((min-h (edb--1ds-min-height ds)) (max-h (edb--1ds-max-height ds))) (when (or min-h max-h) (let ((rep-h (1+ (db-count-newlines rep)))) (cond ((and min-h (< rep-h min-h)) ;; too short (setq rep (concat rep (make-string (- min-h rep-h) ?\n)))) ((and max-h (> rep-h max-h)) ;; too tall (setq rep (substring rep 0 (db-find-char-from-end ?\n rep (- rep-h min-h))))))))) ;; These conditions are much too simplistic; they only work for one-line ;; representations. (let ((rep-w (length rep)) (min-w (edb--1ds-min-width ds)) (max-w (edb--1ds-max-width ds))) (cond ((and min-w (< rep-w min-w)) ;; The display representation is too short (setq rep (funcall (or (edb--1ds-padding-action ds) 'db-pad-right) min-w rep rep-w)) (unless (= (length rep) min-w) (error "Padding function %s returned \"%s\", %s %d, not %d." (or (edb--1ds-padding-action ds) 'db-pad-right) rep "which has length" (length rep) min-w)) (setq rep-w min-w)) ((and max-w (> rep-w max-w)) ;; The display representation is too long. (funcall (or (edb--1ds-truncation-display-action ds) (lambda (max-w rep rep-w) (put-text-property max-w rep-w 'invisible t rep))) max-w rep rep-w) ;; Assume the truncation function did the right thing. (setq rep-w max-w))) rep))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Etc. ;;; (defun database-mode () "A mode for viewing and editing formatted data; a database front end. In Database Edit mode, fields of the database may be changed. In Database View mode, keystrokes are bound to database commands. Typically, if point is on a field, the buffer is in Database Edit mode; if point is at the beginning of the buffer, the buffer is in Database View mode. The mode line indicates which mode the buffer is in. Database View mode key bindings: \\{database-view-mode-map} Database Edit mode key bindings: \\{database-edit-mode-map}" (setq mode-line-modified '(:eval (let ((meta (edb--meta1D dbc-database))) (if (not (gethash :modifiable-p meta)) "%%%%" (string (if (gethash :modp meta) ?* ?-) (if (edb--S :utkmodp) ?* ?-) )))) mode-line-format '("-" mode-line-modified "%*" "- %17b %[(" mode-name minor-mode-alist (:eval (concat (and (edb--S :hide-p) " Hide") " " (edb--S :index-fraction))) ")%]" "---" (-3 . "%p") "-%-")) (make-local-variable 'require-final-newline) (setq require-final-newline nil) (db-view-mode)) (defsubst db-data-display-buffer-p () "T if this buffer is a database data display buffer." (memq major-mode '(database-view-mode database-edit-mode))) ;;; db-format.el ends here edb-1.31/lisp/db-interfa.el0000444000175000017500000016451711016241412013674 0ustar ttnttn;;; db-interfa.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Commands for operating on the current database. ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Variables ;;; (defvar dbc-database nil "The database associated with this format. This variable is also set in the summary format.") (defun dbc-set-hide-p (value) "Enable hiding if VALUE is non-nil, otherwise disable it. This is done in both the data display buffer and summary buffer." (edb--S! :hide-p value) (let ((other (or (edb--S :data-display-buffer) (edb--S :sumbuf)))) (when other (with-current-buffer other (edb--S! :hide-p value))))) ;;; Etc. ;;;###safe-file-local-variable (defvar db-new-record-function nil "Function called on empty records before they're inserted in the database. Takes two arguments, the record and the database. This variable is set only in the data display buffer.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Keymaps ;;; (defvar database-view-mode-map nil "Keymap for database data display buffer in view mode.") (unless database-view-mode-map (let ((m (make-sparse-keymap)) (meta (list meta-prefix-char))) (suppress-keymap m) (mapc (lambda (key-def) (define-key m (let ((key (car key-def))) (if (consp key) (concat meta (car key)) key)) (cdr key-def))) '(("t" . toggle-truncate-lines) ("+" . db-additional-data-display-buffer) ;; Moving around in the database ("n" . db-next-record) ("p" . db-previous-record) ("<" . db-first-record) (">" . db-last-record) (("<") . db-first-record) ((">") . db-last-record) ("j" . db-jump-to-record) (" " . db-next-screen-or-record) ("\177" . db-previous-screen-or-record) (("n") . db-next-record-ignore-hiding) (("p") . db-previous-record-ignore-hiding) (("\C-n") . db-next-marked-record) (("\C-p") . db-previous-marked-record) ;; Changing to edit mode ("\t" . db-first-field) (("\t") . db-last-field) ("\C-n" . db-first-field) ("\C-p" . db-last-field) ("e" . db-first-field) ;; These could be db-first-field and db-last-field, but that ;; wouldn't fit in: nowhere else are these keystrokes ;; inter-field-movement keystrokes. ("\C-f" . undefined) ("\C-b" . undefined) ("\C-a" . undefined) ("\C-e" . undefined) ;; ("v" . db-view-mode) ("\C-v" . db-scroll-up) ;; In view-mode, we're at the top of the buffer (not after ;; db-next-screen). (("v") . db-scroll-down) ;; Undoing changes ("\C-xu" . db-revert-record) ;;("u" . db-revert-record) ("\C-xr" . db-revert-database) ;; Adding and removing records ("a" . db-add-record) ("i" . db-add-record) ("d" . db-delete-record) ("k" . db-delete-record) ("y" . db-yank-record) ("o" . db-output-record-to-db) ("c" . db-copy-record) ;; Sorting ("S" . db-sort) ;; Searching commands (("S") . db-search) (("s") . db-search) ("s" . db-search) ("\C-s" . db-isearch-forward) ("\C-r" . db-isearch-backward) ;; Exiting database mode ("q" . db-quit) ("x" . db-kill-buffer) ("X" . db-kill-all-buffers) ("m" . db-mark-record) ("?" . describe-mode) ;; Gross key bindings. ("O" . db-hide-record) (("o") . db-hiding-toggle) (("O") . db-hiding-set) (("\C-o") . db-toggle-show-hidden-records) ("F" . dbf-set-summary-format) ("D" . db-summary) ; mnemonic for Directory ("h" . db-summary) ; mnemonic for Headers ("H" . db-summary) ; mnemonic for Headers ("r" . db-report) ("\r" . db-accept-record))) (setq database-view-mode-map m))) (defvar database-edit-mode-map nil "Keymap for database data display buffer in edit mode.") (unless database-edit-mode-map (let ((m (make-sparse-keymap)) (meta (list meta-prefix-char))) ;; Obviously don't do suppress-keymap on this one; we want to be ;; able to edit. The view-mode commands should be available via C-c ;; and many (such as next-record) available via M- commands as well, ;; espcially those not ordinarily bound in text mode (eg M-n and ;; M-p). (mapc (lambda (key-def) (define-key m (let ((key (car key-def))) (if (consp key) (concat meta (car key)) key)) (cdr key-def))) '(;; Exiting edit mode ("\C-c\C-c" . db-view-mode) ;; Undoing changes ("\C-xU" . db-revert-field) ;; Moving from record to record (("n") . db-next-record) (("p") . db-previous-record) ;; Moving from field to field ("\t" . db-next-field) (("\t") . db-previous-field) (("<") . db-first-field) ((">") . db-last-field) ("\C-v" . db-scroll-up) (("v") . db-scroll-down) ;; Movement within a field ("\C-n" . db-next-line-or-field) ("\C-p" . db-previous-line-or-field) ;; almost-the-same-as-before commands ("\C-f" . db-forward-char) ("\C-b" . db-backward-char) (("f") . db-forward-word) (("b") . db-backward-word) ("\C-a" . db-beginning-of-line-or-field) ("\C-e" . db-end-of-line-or-field) ;; Editing a field ;;insertion ("\r" . db-newline) ("\n" . db-newline) ("\C-o" . db-open-line) ;;deletion ("\C-d" . db-delete-char) ("\177" . db-backward-delete-char) (("d") . db-kill-word) (("\177") . db-backward-kill-word) ("\C-k" . db-kill-line) (("k") . db-kill-to-end) ("\C-w" . db-kill-region) (("w") . db-copy-region-as-kill) ;; Other commands (("s") . db-search-field) ;;(("S") . db-search-field) ("\C-s" . db-isearch-forward) ("\C-r" . db-isearch-backward) (("?") . db-field-help))) (setq database-edit-mode-map m))) ;;; Bindings for both keymaps (mapc (lambda (&optional key-def) (apply 'define-key database-view-mode-map key-def) (apply 'define-key database-edit-mode-map key-def)) '( ;; Saving the database ("\C-x\C-s" db-save-database) ("\C-x\C-w" db-write-database-file) ;; Toggling modifiable-p ("\C-x\C-q" db-toggle-modifiable-p) ;; Wipe out dangerous commands ("\C-xn" undefined))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Menus ;;; ;; Menus by Alastair Burt , ;; Michael Ernst ;; John Overton (defvar database-view-mode-menu '("Database" "VIEW Mode:" ["Edit" db-first-field t] ["Report" db-report t] ["Summary" db-summary t] "---" ["Revert record" db-revert-record t] ["Accept record" db-accept-record t] ["Add record" db-add-record t] ["Copy record" db-copy-record t] ["Delete record" db-delete-record t] ["Output record" db-output-record-to-db t] ["Mark record" db-mark-record t] ["Hide record" db-hide-record t] "----" ("Hiding" ["Hiding on/off" db-hiding-toggle t] ["Hiding hide/show (in summary)" db-toggle-show-hidden-records t] ["Un-hide all" db-unhide-all t] ["Un-mark all" db-unmark-all t] ["Mark un-hidden" db-mark-unhidden-records t] ["Hide un-marked" db-hide-unmarked-records t] ) ("Motion" ["jump to" db-jump-to-record t] ["first" db-first-record t] ["last" db-last-record t] "---" ["next" db-next-record t] ["next (screen)" db-next-screen-or-record t] ["next (marked)" db-next-marked-record t] ["next (ignore hiding)" db-next-record-ignore-hiding t] "---" ["prev" db-previous-record t] ["prev (screen)" db-previous-screen-or-record t] ["prev (marked)" db-previous-marked-record t] ["prev (ignore hiding)" db-previous-record-ignore-hiding t] ) "----" ["Create Report" db-report t] ["Toggle Hiding" db-hiding-toggle t] ["Summary" db-summary t] "----" ["Edit Mode" db-first-field t] "----" ["Sort database" db-sort t] ["Revert database" db-revert-database t] ["Save database" db-save-database t] ["Write database" db-write-database-file t] ["Internal Layout" db-toggle-internal-file-layout t] "----" ["Quit" db-quit t] ) "Menu for Database View mode.") ;; 'ignored for SYMBOL argument was giving me trouble. ;; Does this work in Lucid Emacs? (easy-menu-define ignored database-view-mode-map "ignored-doc-string" database-view-mode-menu) (defvar database-edit-mode-menu '("Database" "EDIT Mode:" ["View mode" db-view-mode t] ["Report" db-report t] ["Summary" db-summary t] ["Summary subset" db-summary-subset t] "---" ["Revert record" db-revert-record t] "---" ["Revert field" db-revert-field t] ["Help on field" db-field-help t] ["Search in field" db-search-field t] "---" ("Motion" ["Next field" db-next-field t] ["Prev field" db-previous-field t] ["Last field" db-last-field t] ["First field" db-first-field t] ["Next record" db-next-record t] ["Previous record" db-previous-record t]) "---" ["Revert database" db-revert-database t] ["Search database" db-search-field t] ["Save database" db-save-database t] ["Write database" db-write-database-file t] "---" ["Quit" db-quit t] ) "Menu for Database Edit mode.") ;; 'ignored for SYMBOL argument was giving me trouble. ;; Does this work in Lucid Emacs? (easy-menu-define ignored database-edit-mode-map "ignored-doc-string" database-edit-mode-menu) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Help ;;; (defun db-set-field-help (db &rest spec) "Set field-specific help info for database DB from F1 H1, ... F1, F2, ... should be field names (symbols) or field numbers, while H1, H2, ... should be either a string or a form to be evaluated that results in a string. See `db-field-help'. This should be called after the field names have been set up. \(fn DB F1 H1 ...)" (let* ((len (length (database-fieldnames db))) (fh (or (edb--1D db :field-help) (edb--1D! db :field-help (make-vector len nil)))) (nm2no (edb--1D db :nm2no)) field help-info) (while spec (setq field (pop spec) help-info (pop spec)) (aset fh (if (symbolp field) (gethash field nm2no) field) help-info)))) (defun db-field-help () "Display help for the current field in the echo area. Help info comes from two places: field-specific help info, and recordfieldtype-specific help info. In both cases, if the info is a string, display it. Otherwise, `eval' it as a Lisp expression and display the result (which should be a string). When both sources provide the help info, the display the field-specific info followed by two newlines followed by the recordfieldtype-specific info." (interactive) (unless (edb--S :this-ds) (error "Not on a field.")) (flet ((try (x) (when x (if (stringp x) (list "%s" x) (condition-case err (list "%s" (eval x)) (error (list "Help form: %S\nfailed with error: %S" x err))))))) (let* ((fidx (edb--1ds-record-index (edb--S :this-ds))) (one (let ((fh (edb--1D dbc-database :field-help))) (and fh (try (aref fh fidx))))) (two (try (aref (db-rs-slice dbc-database 'edb--1rs-help-info) fidx)))) (if (or one two) (apply 'message (concat (car one) (and one two "\n\n") (car two)) (append (cdr one) (cdr two))) (message "No help available for `%s'." (db-fname<-fno fidx dbc-database)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Quitting ;;; ;; These work in both the data display buffer and the summary buffer, for ;; folks who enjoy spending most of their time in the summary who will rebind ;; its keystrokes to call these functions instead of dbs-exit (for instance). (defun db-quit () "Quit editing the database for now; bury its buffers." (interactive) ;; Bury the data display and summary buffers. (let (dd sum) (db-in-data-display-buffer (setq dd (current-buffer) sum (edb--S :sumbuf))) (when dd (delete-windows-on dd) (bury-buffer dd)) (when sum (delete-windows-on sum) (bury-buffer sum)))) (defun db-kill-buffer (&optional noask) "Kill this data display buffer and any associated summary buffer. Offer to save any changes. Prefix arg means don't offer. See also `db-kill-all-buffers'." (interactive "P") (unless noask (db-save-database t)) (edb--S! :discard-changes! t) (kill-buffer nil)) (defun db-kill-all-buffers (&optional noask) "Kill all buffers associated with the current database. Offer to save any changes. Prefix arg means don't offer. See also `db-kill-buffer'." (interactive "P") (unless noask (db-save-database t)) (dolist (ddb (edb--1D dbc-database :ddbufs)) (with-current-buffer ddb (edb--S! :discard-changes! t) (kill-buffer nil)))) (defun db-exit (&optional kill) "Be done with the database; like `db-quit', but offers to save any changes. With prefix argument, kills the data display buffer, and the database, if that was its only data display buffer." (interactive "P") (db-save-database t) (if kill (db-kill-all-buffers t) (db-quit))) (defun db-kill-buffer-hook () (when (edb--rget '(:edb1 :bprops) (current-buffer)) (cond ((db-summary-buffer-p) (with-current-buffer (edb--S :data-display-buffer) (edb--S! :sumbuf nil))) ((db-data-display-buffer-p) (let ((left (remq (current-buffer) (edb--1D dbc-database :ddbufs))) buf) (unless (edb--S :discard-changes!) (when (and (or (edb--S :utkmodp) (dbf-this-field-modified-p)) (y-or-n-p "Commit current record? ")) (dbf-process-current-record-maybe t)) (db-save-database t left)) (when (setq buf (edb--S :sumbuf)) (delete-windows-on buf) (kill-buffer buf)) (if left (edb--1D! dbc-database :ddbufs left) ;; slightly suboptimal from maintenance pov --ttn (when (setq buf (edb--S :ddb-spec)) (kill-buffer buf)) (edb--meta1D dbc-database :forget))))) (edb--rforget '(:edb1 :bprops) (current-buffer)))) (defun db-save-some-buffers (&optional quietly exiting) "Save some modified databases and file-visiting buffers. Asks user about each one. With argument, saves all with no questions." (interactive "P") (db-save-some-databases quietly) (save-some-buffers quietly exiting)) ;; This isn't quite right because it should modify the ???. (defun db-save-some-databases (&optional quietly) "Save some modified databases. Asks user about each one. With argument, saves all with no questions." (interactive "P") (let (buffers) (dolist (db (edb--1all-known-databases)) (setq buffers (edb--1D db :ddbufs)) (when buffers (dolist (buf buffers) (db-in-buffer buf (dbf-process-current-record-maybe t))) (db-in-buffer (car buffers) (db-save-database (not quietly))) (dolist (buf buffers) (with-current-buffer buf (force-mode-line-update))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; File I/O ;;; ;;;###autoload (defun db-find-file (filename &optional promptp) "Read a database from FILENAME; prompts when called interactively. If the database file doesn't specify a format and the format file can't be inferred from FILENAME, the user is prompted for it too. The user is always prompted for the format if prefix argument PROMPTP is non-nil. If the database is already read in and PROMPTP is nil, the existing database buffer is merely selected. When called non-interactively, argument PROMPTP may be a string, the name of a format file to use." (interactive "fDatabase file: \nP") ;; fixme: check whether the file is currently read in. --ttn (setq filename (expand-file-name filename)) (let ((format-file (when (stringp promptp) promptp)) database data-display-buffer) (when (stringp promptp) (setq promptp nil)) (unless promptp (setq database (db-find-read-in-database filename)) (when (and database (not (edb--1D database :ddbufs))) (setq database nil)) ;; Find an appropriate data display buffer (when (and database format-file) (let ((bufs (edb--1D database :ddbufs)) ddb-format-file) (while bufs (if (db-same-file-p format-file (with-current-buffer (car bufs) (edb--S :format-file))) (setq data-display-buffer (car bufs) bufs nil) (setq bufs (cdr bufs))))))) (unless database ;; Either promptp is non-nil, or we couldn't find an ;; appropriate read-in-database. (setq database (db-read-database-file filename format-file promptp))) (unless data-display-buffer (setq data-display-buffer (car (edb--1D database :ddbufs)))) (switch-to-buffer data-display-buffer) (assert (eq (current-buffer) (variable-binding-locus 'dbc-database))) (setq dbc-database database)) (db-first-record)) (defun db-find-read-in-database (filename) ;; Return the database most recently read in from FILENAME, or nil. (let ((db-ls (edb--1all-known-databases)) result db maybe) (while (and (not result) db-ls) (setq db (car db-ls) maybe (edb--1D db :file) result (when (and (db-same-file-p filename (if (equal "(inherent)" maybe) (get-text-property 0 :file maybe) maybe)) (car (edb--1D db :ddbufs))) db) db-ls (cdr db-ls))) result)) (defun db-revert-database () "Replace the database with the data on disk. This undoes all changes since the database was last saved." (interactive) (when (yes-or-no-p (format "Revert database from file %s? " (edb--1D dbc-database :file))) (let ((database dbc-database)) (with-temp-buffer (insert-file-contents (edb--1D database :file) nil) (unless (setq database (db-read-database-internal-file-layout)) (error "File no longer contains a database")) (db-read-database-file-helper database)) (mapc (lambda (buf) (with-current-buffer buf ;; abandon any changes (dbf-set-this-field-modified-p nil) (edb--S! :utkmodp nil) (db-jump-to-record (edb--S :index) nil))) (edb--1D database :ddbufs)) (db-message "Reverted database from disk")))) (defun db-save-database (&optional query quietly) "Save the database to disk in the default save file. Any changes to the current record are processed first. The default save file is the file it was last saved to or read from. If optional arg QUERY is specified, the user is asked first. Optional second arg QUIETLY suppresses messages regarding the filename." (interactive) ;; fixme: check if file is more recent than buffer. --ttn (db-in-data-display-buffer (dbf-process-current-record-maybe t) (if (edb--1D dbc-database :modp) (when (or (not query) (yes-or-no-p (concat "Save database " (database-print-name dbc-database) "? "))) (db-write-database-file (edb--1D dbc-database :file) quietly)) (unless quietly (let ((name (database-print-name dbc-database))) (when (and (stringp name) (or (string= "" name) (string= "Unnamed Database " (substring name 0 (min 17 (length name)))))) (setq name nil)) (db-message "No changes need to be saved%s" (if name (format " in %S" name) ""))))))) (defun db-write-database-file (&optional filename quietly) "Save the database to file FILENAME; it becomes the default save file. Any changes to the current record are processed first. If FILENAME is not specified, the user is prompted for it. Optional second arg QUIETLY suppresses messages regarding the filename." (interactive) ;; Do this before asking for the filename. (dbf-process-current-record-maybe t) ;; Save even if the database is not modified. (unless filename (setq filename (read-file-name (format "Save database %s into file: " (database-print-name dbc-database))))) (unless (equal filename (edb--1D dbc-database :file)) (edb--1D! dbc-database :file filename) ;; Rename the buffer. (rename-buffer (generate-new-buffer-name (file-name-nondirectory filename)))) (when (equal "(inherent)" filename) (setq quietly t) (db-message "Saving %s..." (buffer-name))) (let ((msg (format "Saving database to file %s..." filename))) (unless quietly (db-message "%s" msg)) (db-write-1) (unless (or quietly (edb--G :io-error-p)) (db-message "%sdone" msg)))) (defun db-toggle-internal-file-layout (&optional arg) "Toggle whether the database will be saved in EDB's internal file layout. With a nonzero prefix argument, set it to use internal file layout. With a zero prefix argument, set it not to use internal file layout." (interactive "P") (let ((v (if arg (not (zerop (prefix-numeric-value arg))) (not (edb--1D dbc-database :togp))))) (edb--1D! dbc-database :togp v) (when (interactive-p) (message "Use of internal file layout now %sabled" (if v "en" "dis"))))) (defun db-toggle-modifiable-p (&optional arg) "Toggle whether the database may be modified by the user. With a nonzero prefix argument, set it modifiable. With a zero prefix argument, set it non-modifiable." (interactive "P") (let ((modifiable-p (if arg (not (zerop (prefix-numeric-value arg))) (not (edb--1D dbc-database :modifiable-p))))) (edb--1D! dbc-database :modifiable-p modifiable-p) ;; fixme: handle mods in the presence of nil `modifiable-p'. --ttn (db-in-data-display-buffer (when (eq 'database-edit-mode major-mode) (setq buffer-read-only (not modifiable-p))) (set-buffer-modified-p (buffer-modified-p))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Record selection ;;; ;; This is the common body of `db-next-record' and `db-jump-to-record'. (defmacro dbf-goto-record-internal (&rest record-selector-body) (declare (indent 0) (debug body)) `(progn ;; NOTE: This line will cause problems if some hook function ;; deliberately raises an error (like Joe Wells' do). (db-view-mode) (dbf-process-current-record-maybe nil) ,@record-selector-body (edb--S! :original (aref (edb--1D dbc-database :vov) (1- (edb--S :index)))) (db-display-record (dbf-displayed-record) t))) (defun db-jump-to-record (arg &optional respect-hiding) "Show the database's ARGth record. If ARG is a record, use its index. Hiding is ignored unless optional argument RESPECT-HIDING is specified." ;; NOTE: Respect and ignorance have opposite nature. (interactive "NJump to record number: ") (unless (integerp arg) (let ((vov (edb--1D dbc-database :vov)) (rno (edb--1D dbc-database :nrecords)) (i 0)) ;; linear search, blech (while (and (< i rno) (not (integerp arg))) (when (eq (aref vov i) arg) (setq arg (1+ i))) (incf i)) (unless (integerp arg) ;; make `db-select-record' throw out-of-range error (setq arg -1)))) (db-in-data-display-buffer (dbf-goto-record-internal (db-select-record arg (not respect-hiding)))) (when (db-summary-buffer-p) (dbs-synch-summary-with-format))) (defun db-first-record (&optional ignore-hiding) "Show the database's first record. With optional prefix argument, ignores hiding." (interactive "P") (cond ((db-data-display-buffer-p) (db-jump-to-record 1 (not ignore-hiding))) ((db-summary-buffer-p) ;; fixme: handle hiding. --ttn (goto-char (point-min)) (db-jump-to-point)) (t (error "db-first-record called in wrong context.")))) (defun db-last-record (&optional ignore-hiding) "Show the database's last record. With optional prefix argument, ignores hiding." (interactive "P") (cond ((db-data-display-buffer-p) (db-jump-to-record (edb--1D dbc-database :nrecords) (not ignore-hiding))) ((db-summary-buffer-p) (goto-char (point-max)) (db-jump-to-point)) (t (error "db-last-record called in wrong context")))) (defun db-next-record (arg &optional ignore-hiding markedp) "Go to the ARGth next record. In that record, go to the current field, if any." (interactive "p") (when (db-summary-buffer-p) (dbs-synch-format-with-summary)) (db-in-data-display-buffer (let ((this-fidx (edb--S :this-fidx))) (dbf-goto-record-internal (db-select-next-record arg ignore-hiding markedp)) ;; If in edit mode, stay in edit mode in the same field. (when (and this-fidx (edb--S :stay-in-edit-mode-p)) (db-move-to-field-exact this-fidx)))) (when (db-summary-buffer-p) (let ((index (with-current-buffer (edb--S :data-display-buffer) (edb--S :index)))) ;; This might not be right, depending on what records are summarized. (dbs-forward-record (- index (edb--S :index))) (dbs-set-index index)))) (defsubst db-previous-record (arg &optional ignore-hiding markedp) "Go to the ARGth previous record. In that record, go to the current field, if any." (interactive "p") (db-next-record (- arg) ignore-hiding markedp)) (defsubst db-next-record-ignore-hiding (arg) "Go to the ARGth next record, ignoring omissions. That is, all records, even those which are hidden, are counted." (interactive "p") (db-next-record arg t)) (defsubst db-previous-record-ignore-hiding (arg) "Go to the ARGth previous record, ignoring omissions. That is, all records, even those which are hidden, are counted." (interactive "p") (db-next-record-ignore-hiding (- arg))) (defsubst db-next-marked-record (arg) "Go to the ARGth next marked record. Hidden records are treated according to db-hide-p." (interactive "p") (db-next-record arg nil t)) (defsubst db-previous-marked-record (arg) "Go to the ARGth previous marked record. Hidden records are treated according to db-hide-p." (interactive "p") (db-next-marked-record (- arg))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Moving from record to record (setting :index) ;;; ;; These don't display, but they do set `:index'. ;; Don't forget that when moving off a record, must check whether it has ;; been modified and, if so, call an update function. (defun dbc-set-index (index &optional record) (unless record (setq record (aref (edb--1D dbc-database :vov) (1- index)))) (edb--S! :index index) (edb--S! :index-fraction (let ((frac (format "%s%d/%d" (if (edb-tagp (edb-tag :markedp dbc-database) record) "+" "") index (edb--1D dbc-database :nrecords)))) (if (and (edb--S :hide-p) (edb-tagp (edb-tag :hiddenp dbc-database) record)) (concat "[" frac "]") frac)))) (defun db-select-next-record (n &optional ignore-hiding markedp) ;; Set new `:index' to point the Nth following, or if N is negative, ;; the -Nth preceding, record. Respect `:hide-p' and `:wraparound'. (interactive "p") (let* ((up (< 0 n)) (hidep (and (edb--S :hide-p) (not ignore-hiding))) (wrapp (or (eq t (edb--S :wraparound)) (and (eq 'delay (edb--S :wraparound)) (eq :failed last-command)))) (idx (edb--S :index)) (vov (edb--1D dbc-database :vov)) (rno (edb--1D dbc-database :nrecords)) (new (flet ((new-idx (delta) (1+ (% (+ rno delta -1 idx) rno)))) (if (or hidep markedp) ;; slow path (let ((sign (if up 1 -1)) (good nil) (stop (cond (wrapp idx) (up rno) (t 1))) (htag (and hidep (edb-tag :hiddenp dbc-database))) (mtag (and markedp (edb-tag :markedp dbc-database))) record) (while (not (or (zerop n) (if (not wrapp) (prog1 (= idx stop) (setq idx (new-idx sign))) (setq idx (new-idx sign)) (= idx stop)))) (setq record (aref vov (1- idx))) (unless (or (and htag (edb-tagp htag record)) (and mtag (not (edb-tagp mtag record)))) (setq good idx) (decf n sign))) (or good (edb--S :index))) ;; fast path (new-idx (cond (wrapp n) (up (min n (- rno idx))) (t (max n (- 1 idx))))))))) (dbc-set-index (if (/= new (edb--S :index)) new (setq this-command :failed) new) (aref vov (1- new))) (when (eq :failed this-command) (message "%s record" (if up "Last" "First"))))) (defun db-select-first-record (&optional ignore-hiding) ;; Select first record. Does no display. ;; If hiding is in effect, select the first unhidden record, unless ;; optional argument IGNORE-HIDING is non-nil. (interactive) (if (and (edb--S :hide-p) (not ignore-hiding) (edb-tagp (edb-tag :hiddenp dbc-database) (aref (edb--1D dbc-database :vov) 0))) (progn (edb--S! :index 1) (db-select-next-record 1)) (dbc-set-index 1))) (defun db-select-record (index &optional ignore-hiding) ;; Select record at INDEX. Throw error if INDEX out of range. ;; If that record is hidden, select the first following non-hidden record, ;; unless optional argument IGNORE-HIDING is non-nil. (interactive "nRecord number: ") (let ((rno (edb--1D dbc-database :nrecords))) (unless (and (<= 1 index) (<= index rno)) (error "Record number %d out of range 1..%d" index rno))) (db-select-first-record ignore-hiding) (db-select-next-record (1- index) ignore-hiding)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Hybrid field/record movement commands ;;; (defun db-next-screen-or-record (arg) "Go to the ARGth next screenful of this display, or to the ARGth next record, if this is the last screenful of this display. If point is in the summary buffer and the data display buffer is not visible, then move to the next record." (interactive "p") (cond ((db-data-display-buffer-p) (dbf-next-screen-or-record arg)) ((db-summary-buffer-p) (let ((w (get-buffer-window (edb--S :data-display-buffer)))) (if w (progn (with-selected-window w (dbf-next-screen-or-record arg)) (dbs-synch-summary-with-format)) (db-next-record arg)))))) (defun dbf-next-screen-or-record (arg) (let ((pmax (point-max))) (if (= pmax (window-end)) (db-next-record arg) (while (and (> arg 0) (not (= pmax (window-end)))) (scroll-up nil) (decf arg))))) (defun db-previous-screen-or-record (arg) "Go to the ARGth previous screenful of this display, or to the ARGth previous record, if this is the first screenful of this display. If point is in the summary buffer and the data display buffer is not visible, then move to the previous record." (interactive "p") (cond ((db-data-display-buffer-p) (dbf-previous-screen-or-record arg)) ((db-summary-buffer-p) (let ((w (get-buffer-window (edb--S :data-display-buffer)))) (if w (progn (with-selected-window w (dbf-previous-screen-or-record arg)) (dbs-synch-summary-with-format)) (db-previous-record arg)))))) (defun dbf-previous-screen-or-record (arg) (let ((pmin (point-min))) (if (= pmin (window-start)) (db-previous-record arg) (while (and (> arg 0) (not (= pmin (window-start)))) (scroll-down nil) (decf arg)) (when (= pmin (window-start)) (goto-char (point-min)))))) (defun db-beginning-of-field-or-record () "Move to the beginning of this field. If already at its beginning, move to the first field." (interactive) (if (= (point) (edb--S :fbeg)) (db-first-field) (db-beginning-of-field))) (defun db-end-of-field-or-record () "Move to the end of this field; if at its end, to the last field." (interactive) (if (= (point) (dbf-this-field-end-pos)) (db-last-field) (db-end-of-field))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Adding and deleting records ;;; (defun db-add-record (&optional append) "Add a new record to the database immediately before the current record. Prefix arg APPEND means to add after the last record, instead. After adding, move point to the new record's first field and switch to Database Edit mode." (interactive "P") (when (db-summary-buffer-p) (pop-to-buffer (edb--S :data-display-buffer))) (let* ((nfields (length (database-fieldnames dbc-database))) (defaults-slice (db-rs-slice dbc-database 'edb--1rs-default-value)) (new (make-vector nfields nil))) (dotimes (fno nfields) (aset new fno (aref defaults-slice fno))) (when db-new-record-function (funcall db-new-record-function new dbc-database)) (database-add-record new dbc-database (unless append (edb--S :index)))) (edb--S! :index (if append (edb--1D dbc-database :nrecords) (1+ (edb--S :index)))) ;; Why doesn't this need to be (dbc-set-modified-p t)? (database-set-modified-p dbc-database t) ;; Probably unnecessary, as `database-add-record' has done the trick. (dbf-set-summary-out-of-date-p) ;; fixme: update incrementally instead of fully. --ttn (let ((sumbuf (edb--S :sumbuf))) (when (and sumbuf (get-buffer-window sumbuf)) (db-in-buffer sumbuf (dbs-synch-summary-with-format)))) (db-previous-record (if append 0 1)) (db-message "%sed a new record" (if append "Append" "Insert")) ;; Begin editing the new record. Don't use `db-edit-mode'. (db-first-field)) (defun db-delete-record (&optional force) "Remove the current record from the database. With a prefix argument, doesn't verify." ;; fixme: handle "no more records" situation --ttn (interactive "P") (when (or force (y-or-n-p "Delete this record? ")) (let ((cur (edb--S :index)) (vov (edb--1D dbc-database :vov)) (rno (edb--1D dbc-database :nrecords))) ;; stash (edb--1D! dbc-database :deleted-record (aref vov (1- cur))) ;; shift down and clear highest (do ((i (1- cur) (1+ i))) ((= (1- rno) i)) (aset vov i (aref vov (1+ i)))) (aset vov (decf rno) nil) (edb--1D! dbc-database :nrecords rno) (edb--S! :index (if (= 1 cur) ; ugh rno (1- cur)))) ;; update the summary directly (database-set-modified-p dbc-database t) (db-message "Record deleted") (db-next-record 1))) (defun db-yank-record (endp) "Insert, and make current, the most recently deleted record. The deleted record is inserted before the current record. With prefix argument ENDP, insert at end of database and don't select it." (interactive "P") (unless (edb--1D dbc-database :deleted-record) (error "No deleted record to yank.")) (db-in-data-display-buffer ;; This is inelegant in the extreme, but the interaction of ;; `dbc-set-index' and db-{previous-next}-record and ;; `database-add-record' mystifies me. --karl@owl.hq.ileaf.com (Karl Berry) (database-add-record (edb--1D dbc-database :deleted-record) dbc-database (unless endp (edb--S :index))) (if endp ;; We go back to the current record below. (db-next-record 1) (dbc-set-index (1+ (edb--S :index))) (db-previous-record 1) (database-set-modified-p dbc-database t))) (when (db-summary-buffer-p) (dbs-synch-summary-with-format)) (force-mode-line-update) (db-message "Record yanked")) (defun db-copy-record (&optional arg) "Insert a copy of the current record in the database immediately after it. The second of the two records is made the current record. With a prefix argument, inserts that many copies." (interactive "p") (db-in-data-display-buffer (dbf-process-current-record-maybe t) (let* ((vov (edb--1D dbc-database :vov)) (rec (aref vov (1- (edb--S :index))))) (while (> arg 0) (database-add-record (copy-sequence rec) dbc-database (edb--S :index)) (dbc-set-index (1+ (edb--S :index))) (decf arg)))) (when (db-summary-buffer-p) (dbs-synch-summary-with-format)) (force-mode-line-update) (db-message "Record copied")) (defun db-output-record-to-db (db) "Copy (output) the current record to database DB. DB must be read in and compatible with the current database." ;; Make a list of databases compatible with this one. (interactive (list (let ((last (edb--1D dbc-database :db-for-output)) choices sel) (dolist (db (edb--1all-known-databases)) (when (and (not (eq db dbc-database)) (databases-compatible db dbc-database)) (push (cons (or (database-print-name db) (edb--1D db :file)) db) choices))) (unless choices (error "No compatible databases are currently read in!")) (unless (and last (member last (mapcar 'car choices))) (edb--1D! dbc-database :db-for-output (setq last nil))) (setq sel (completing-read "Output record to which database (? for choices): " choices nil t last)) (unless (string= "" sel) (edb--1D! dbc-database :db-for-output sel)) (cdr (assoc sel choices))))) (when db (when (db-summary-buffer-p) (dbs-synch-format-with-summary)) (with-current-buffer (if (db-summary-buffer-p) (edb--S :data-display-buffer) (current-buffer)) (let ((rec (aref (edb--1D db :vov) (1- (edb--S :index))))) (db-in-data-display-buffer (database-add-record rec db)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Sorting ;;; (defun db-sort (&optional dont-confirm) "Sort the database. With a prefix argument, don't confirm the sort order." (interactive "P") (let ((cur (current-buffer))) (db-in-data-display-buffer (dbf-process-current-record-maybe t) ;; Save current record for the sake of `dbf-finished-sorting'. (edb--S! :record/before-sorting (aref (edb--1D dbc-database :vov) (1- (edb--S :index)))) (edb--S! :buffer/before-sorting cur) (if dont-confirm (progn (database-sort dbc-database) (dbf-finished-sorting)) (database-sort-interface dbc-database))))) (defun dbf-finished-sorting () ;; Recompute the current record's index, dropping the saved ref immediately. (let ((rec (prog1 (or (edb--S :record/before-sorting) (aref (edb--1D dbc-database :vov) 0)) (edb--S! :record/before-sorting nil)))) (dbc-set-index (catch t (db-lmap (lambda (record) (when (eq rec record) (throw t db-lmap-index))) dbc-database)) rec)) (let (sumbuf window) (when (setq sumbuf (edb--S :sumbuf)) ;; Force summary refresh (due to re-ordering only) and maybe display. (with-current-buffer sumbuf (edb--S! :nrecords -1)) (if (setq window (get-buffer-window sumbuf)) (with-selected-window window (db-summary)) (save-window-excursion (with-current-buffer sumbuf (db-summary)))))) ;; The index shown in the mode line is correct, but the database may have ;; been marked as modified, and that change hasn't made it to the mode line. (force-mode-line-update) (switch-to-buffer (prog1 (or (edb--S :buffer/before-sorting) (current-buffer)) (edb--S! :buffer/before-sorting nil)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Editing ;;; (defun db-field-query-replace () "Replace some instances of a value in this field with some other value. Confirms before each replacement." (interactive) (unless (edb--S :this-fidx) (error "Call this when on a field.")) (let* ((iftxt (edb--S :iftxt)) (cur-idx (edb--S :index)) (dispspec (edb--S :this-ds)) (fsno (edb--S :this-fidx)) (ridx (edb--1ds-record-index dispspec)) (fname (db-fname<-fno ridx dbc-database)) (ordfunc (db-rs-ordfunc (aref (edb--1D dbc-database :elaborated-rfspecs) ridx))) ov ; original value ov-printed rv ; replacement value rv-printed) (dbf-process-current-record-maybe nil) (setq ov (db-callconvert (edb--1ds-display->actual dispspec) (read-string "Query replace: ") ;; No previous value or record. nil nil ridx)) (db-check-constraint ov nil ridx dbc-database) ;; Must keep in mind that this is not necessarily what the user typed. (setq ov-printed (db-callconvert (edb--1ds-actual->display dispspec) ov nil ridx)) (setq rv (db-callconvert (edb--1ds-display->actual dispspec) (read-string (format "Query replace %s with: " ov-printed)) nil nil ridx)) (db-check-constraint rv nil ridx dbc-database) (setq rv-printed (db-callconvert (edb--1ds-actual->display dispspec) rv nil ridx)) (db-maprecords (lambda (record) (when (= 0 (funcall ordfunc ov (aref record ridx))) (db-display-record record t) (db-skip-string-forward (aref iftxt 0)) (edb--S! :this-fidx 0) (db-next-field-internal fsno) ;; fixme: handle strings too big for minibuffer. --ttn (when (y-or-n-p (format "(%s) Replace `%s' with `%s'? " fname ov-printed rv-printed)) ;; It's a bit extreme that this errs if the value ;; fails to meet the constraint. (db-check-constraint rv record ridx dbc-database) (aset record ridx rv))))) (db-message "Replacement done") (db-jump-to-record cur-idx t))) (defun db-accept-record () "Install the current record in the database; make any changes permanent." (interactive) (dbf-process-current-record-maybe t)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Searching ;;; (defun db-search-field (pattern &optional mark) "Search for occurrences of PATTERN in the current field of any record. Finds the first match after the current record; wraps around automatically. With prefix argument, marks all matches in addition to going to the first one. If hiding is in effect, hidden records are ignored." (interactive (list (let ((this-fidx (edb--S :this-fidx))) (unless this-fidx (error "Not on a field in a data display buffer.")) (read-string (format "Search in %s for: " (dbf-this-field-name (edb--S :this-ds))) (aref (edb--S :search-defaults) this-fidx))) current-prefix-arg)) (if (equal "" pattern) (error "You didn't enter a pattern for which to search.")) (let* ((cur-rec (aref (edb--1D dbc-database :vov) (1- (edb--S :index)))) (mtag (edb-tag :markedp dbc-database)) (this-ds (edb--S :this-ds)) (pat (db-parse-match-pattern pattern this-ds)) (pdisp (db-print-match-pattern pat this-ds)) (ridx (edb--1ds-record-index this-ds)) (rs (aref (edb--1D dbc-database :elaborated-rfspecs) ridx)) (this-field-index (edb--S :this-fidx)) this-field (fname (dbf-this-field-name this-ds)) ;; success is t if we've already found some match. ;; The idea is that we'll move to the record at success-index when ;; we're done with the search; if success is nil then we're looking ;; for such a record. This is either because we haven't found one or ;; because we have only found one before :index in the database. success success-record success-index (matches 0)) (aset (edb--S :search-defaults) this-field-index pdisp) (if mark (db-message "Marking all %s in %s..." pdisp fname) (db-message "Searching in %s for %s..." fname pdisp)) (db-lmap (lambda (record) (when (or mark (not success)) (setq this-field (aref record ridx)) (when (db-match pat this-field rs) (if (not success) (setq success-record record success-index db-lmap-index success t)) (when mark (incf matches) (edb-tagx mtag record)))) ;; We're looking for a match in some record besides the displayed ;; one and, preferrably, after it. This permits the first success ;; succeeding the current record to overwrite the first success ;; preceding the current record. This means that searches can't ;; abort after a success, since that success might be before the ;; current record. (when (eq record cur-rec) (setq success nil))) dbc-database (edb--S :hide-p)) (if success-index (if (= (edb--S :index) success-index) (db-message "This record has the only match for %s" pdisp) ;; This takes care of committing any changes to the current record. (dbf-goto-record-internal (dbc-set-index success-index success-record)) (db-move-to-field-exact this-field-index) (if mark (progn (dbf-set-summary-out-of-date-p) (db-message "Searching for %s...marked %s matches" pdisp matches)) (db-message "Searching for %s...found" pdisp))) (db-message "Couldn't find a match in %s for %s" fname pdisp)))) (defun db-search () "`db-search' is not yet implemented; use `db-search-field' instead. In a future version of EDB, `db-search' will permit searching on all fields of a record simultaneously." (interactive) (error "Unimplemented; use db-search-field instead (M-s from Edit mode).")) ;; fixme: convert to after-command hooks. --ttn (defun db-isearch-forward () "Like isearch-forward, but maintains the correspondence between the format and summary buffers." (interactive) (isearch-forward) (db-jump-to-point)) (defun db-isearch-backward () "Like isearch-backward, but maintains the correspondence between the format and summary buffers." (interactive) (isearch-backward) (db-jump-to-point)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Hiding ;;; (defun db-mark-record (&optional arg) "Toggle whether the current record is marked. With a nonzero prefix argument, set it to be marked. With a zero prefix argument, set it to be unmarked." (interactive "P") (db-in-data-display-buffer (let* ((mtag (edb-tag :markedp dbc-database)) (idx (edb--S :index)) (rec (aref (edb--1D dbc-database :vov) (1- idx)))) (funcall (if (if arg (not (zerop (prefix-numeric-value arg))) (not (edb-tagp mtag rec))) 'edb-tagx 'edb-tag-) mtag rec) (dbf-update-summary-item idx) (dbc-set-index idx rec) (force-mode-line-update)))) (defun db-hide-record (&optional arg) "Change whether the current record is hidden. With a nonzero prefix argument, set it to be hidden. With a zero prefix argument, set it to be unhidden." (interactive "P") (db-in-data-display-buffer (let* ((htag (edb-tag :hiddenp dbc-database)) (idx (edb--S :index)) (rec (aref (edb--1D dbc-database :vov) (1- idx)))) (funcall (if (if arg (not (zerop (prefix-numeric-value arg))) (not (edb-tagp htag rec))) 'edb-tagx 'edb-tag-) htag rec) (if (edb--S :hide-p) (dbf-update-summary-item idx) ;; Automatically turn on the effect of hiding. (dbc-set-hide-p t) ;; Update all marks, since potentially all have to be displayed now. (dbf-update-summary-marks)) (dbc-set-index idx rec) (force-mode-line-update)))) (defun db-mark-searched-records () "Mark all records found in search STRING of FIELD." (interactive) (setq current-prefix-arg "1") (call-interactively 'db-search-field "1") (let ((sumbuf (edb--S :sumbuf))) (when sumbuf (save-window-excursion (switch-to-buffer-other-window sumbuf) (dbs-synch-format-with-summary))))) (defun db-hide-unmarked-records () "Hide all unmarked records. Also, clear mark bits and enable hiding." (interactive) (db-in-data-display-buffer (let ((mtag (edb-tag :markedp dbc-database)) (htag (edb-tag :hiddenp dbc-database))) (db-lmap (lambda (record) (if (edb-tagp mtag record) (edb-tag- mtag record) (edb-tagx htag record))) dbc-database t)) (dbc-set-hide-p t) (dbf-update-summary-marks) ;; fixme: redisplay? --ttn )) (defun db-mark-unhidden-records () "Mark all unhidden records. Also clears all hide bits." (interactive) (db-in-data-display-buffer (let ((hiddenp (edb-tag :hiddenp dbc-database)) (markedp (edb-tag :markedp dbc-database))) (db-lmap (lambda (record) (if (edb-tagp hiddenp record) (edb-tag- hiddenp record) (edb-tagx markedp record))) dbc-database)) (dbc-set-hide-p t) (dbf-update-summary-marks) ;; fixme: redisplay? --ttn )) (defun db-unhide-all () "Clear the hide bit of every record." (interactive) (db-in-data-display-buffer (let ((htag (edb-tag :hiddenp dbc-database))) (db-lmap (lambda (record) (edb-tag- htag record)) dbc-database)) (dbc-set-index (edb--S :index)) (force-mode-line-update) (dbf-update-summary-marks))) (defun db-unmark-all () "Clear the mark bit of every record." (interactive) (db-in-data-display-buffer (let ((mtag (edb-tag :markedp dbc-database))) (db-lmap (lambda (record) (edb-tag- mtag record)) dbc-database)) (dbc-set-index (edb--S :index)) (force-mode-line-update) (dbf-update-summary-marks))) (defun db-hiding-toggle (&optional arg) "Change whether hiding is in effect. With a nonzero prefix argument, turn hiding on. With a zero prefix argument, turn hiding off. This does not change the current hide-function, and a hide bit is always computed for each record, but hide bits have no effect on any operations if hiding is not in effect." (interactive "P") (db-in-data-display-buffer (dbc-set-hide-p (if arg (not (zerop (prefix-numeric-value arg))) (not (edb--S :hide-p)))) ;; Refill summary buffer whenever displayed set of records changes, ;; including when switching to no hiding and showing hidden records. (cond ((edb--S :invisible-hidden-p) ;; If the hidden records weren't being shown, the records that ;; should be displayed in the summary buffer just changed. (dbf-fill-summary-buffer t)) (t (dbf-update-summary-marks))) (force-mode-line-update) (db-message "Hiding is now %sin effect" (if (edb--S :hide-p) "" "not ")))) (defun db-hiding-set () "Set the criteria for automatically determining whether to hide a record. This isn't implemented yet." (interactive) (error "db-hiding-set is not yet implemented.")) (defun db-toggle-show-hidden-records (&optional arg) "Toggle whether hidden records are shown in the summary. With a nonzero prefix argument, show hidden records in the summary. With a zero prefix argument, don't show hidden records in the summary." (interactive "P") (db-in-data-display-buffer (let ((inv-p (if arg (zerop (prefix-numeric-value arg)) (not (edb--S :invisible-hidden-p)))) (sumbuf (edb--S :sumbuf))) (edb--S! :invisible-hidden-p inv-p) (if (not inv-p) ;; If we weren't showing hidden records, we might as well start from ;; scratch in filling the summary buffer. (dbf-fill-summary-buffer t) (when sumbuf (db-in-buffer sumbuf (let ((buffer-read-only nil)) (goto-char (point-min)) (delete-matching-lines "^.\\[") (dbs-move-to-proper-record))))) (db-message "Hidden records will %snow be shown" (if inv-p "not " ""))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Reporting ;;; (defun db-report (filename &optional markedp) "Create a report according to format specifications in FILENAME. Prefix argument MARKEDP, if non-nil, means report on only marked records. If hiding is in effect, hidden records are not reported upon. When called interactively, prompt for FILENAME." (interactive (list (let* ((ddb-spec (edb--S :ddb-spec)) (conn (when ddb-spec (with-current-buffer ddb-spec (get-text-property (point-min) :connection)))) (tspec (when conn (edb--with-callable-connection conn (plist-get (conn :schema) :report))))) (or tspec (read-file-name "Report format file: " nil nil t))) current-prefix-arg)) (dbf-process-current-record-maybe t) (let* ((db dbc-database) (lasfl (db-format->lines/sforms (cond ((consp filename) (plist-get filename :text)) ((stringp filename) (with-temp-buffer (insert-file-contents filename) (buffer-string)))) db nil nil t)) (rfunc `(lambda (formatted-record) (insert ,@(cdr lasfl)))) (hide-p (edb--S :hide-p)) (mtag (edb-tag :markedp db))) (switch-to-buffer (get-buffer-create "*Database Report*")) (setq buffer-read-only nil) (erase-buffer) (db-lmap (lambda (record) (when (or (not markedp) (edb-tagp mtag record)) (funcall rfunc record))) db hide-p) (goto-char (point-min)))) ;;; db-interfa.el ends here edb-1.31/lisp/db-isbn.el0000444000175000017500000001122210745616666013210 0ustar ttnttn;;; db-isbn.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; ISBN type for EDB. ;; An ISBN number uniquely identifies a book; it is a string, one of ;; * null string (unknown ISBN) ;; * a dash (this book has not been assigned an ISBN) ;; * a 13-character string computed of numbers, dashes, and X. ;; The last digit is a check digit. ;;; Code: (provide 'db-isbn) ;;; ;;; Display type ;;; (edb-define-displaytype 'isbn 'string-or-nil :max-height 1) ;;; ;;; Field type ;;; (edb-define-recordfieldtype 'isbn 'string-or-nil :type 'isbn :default-value "" :help-info "International Standard Book Number" :constraint-function 'db-isbn-constraint) ;;; ;;; Constraints ;;; (defun db-isbn-constraint (val rec fno db) "Check an isbn." (unless (stringp val) (error "ISBN val %s should be a string." val)) ;; Return t if all the tests succeed. (or (string-equal val "") (string-equal val "-") (progn (unless (= (length val) 13) (error "Bad length %d for ISBN %s; should be 13" (length val) val)) (unless (string-match "\\`[0-9]+-[0-9]+-[0-9]+-[0-9xX]\\'" val) (error "Malformed ISBN %s" val)) ;; Verify the check digit. (let ((check-digit ;; From _Numbers, Groups and Codes_ by J.F. Humphreys and ;; M. Y. Prest, Cambridge University Press, Avon: 1989. page ;; 233. Example: A well-known example of error-correction is ;; provided by the ISBN (International Standard Book Number) of ;; published books. This is a sequence of nine digits ;; a1a2...a9, where each ai is one of the numbers 0,1,...,9, ;; together with a check digit which is one of the symbols ;; 0,1,2,3,4,5,6,7,8,9, or X (with X representing 10). This ;; last digit is included so as to give a check that the ;; previous 9 digits have been correctly transcribed, and is ;; calculated as follows. Form the integer 10a1 + 9a2 + 8a3 ;; +... +2a9 and reduce this modulo 11 to obtain an integer b ;; between 1 and 11 inclusive. The check digit is obtained by ;; subtracting b from 11. (let ((factor 10) (checksum 0) (index 0) digit) ;; factor is the polynome factor for each digit. Since we ;; already checked the format of the isbn, we don't need to ;; do extensive tests here. Factor begins at 10 and goes down ;; to 2 at the last (non-dash) digit excluding the check ;; digit. checksum is the check sum and index is the current ;; digit in the isbn string. (while (>= factor 2) ;; Extract the digit (setq digit (aref val index)) (incf index) ;; If the digit is not a dash then it's a part of the ;; polynome. (unless (= digit ?-) (incf checksum (* factor (- digit ?0))) (decf factor))) ;; Last part of the computation. (setq checksum (- 11 (% checksum 11))) ;; Hack due to difference in the modulo function. (when (= checksum 11) (setq checksum 0)) ;; Convert to a string, if the sum is 10 then the string is ;; "X". The string is the value of the computation. (if (= checksum 10) "X" (number-to-string checksum))))) (unless (string= check-digit (upcase (substring val 12 13))) (error "Check digit should be %s in ISBN %s" check-digit val))) t))) ;;; db-isbn.el ends here edb-1.31/lisp/db-lemacs.el0000444000175000017500000000752610745616666013535 0ustar ttnttn;;; db-lemacs.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; This file collects all the previously scattered support for Lucid Emacs. ;; WARNING: Maintainer does not use Lucid Emacs so this code is not tested. ;;; Code: (unless (get 'emacs-version 'edb-running-lemacs) (error "Do not load `db-lemacs' by itself; loading `database' is enough")) ;; ;; formerly in db-format.el ;; (or (find-face 'db-inter-field-face) (make-face 'db-inter-field-face)) (or (face-differs-from-default-p 'db-inter-field-face) (copy-face 'bold 'db-inter-field-face)) (add-hook 'db-display-record-redo-inter-field-text-function (lambda (buf ls) (save-excursion (set-buffer buf) (if (null ls) (map-extents (lambda (x y) (delete-extent x)) (current-buffer) (point-min) (point-max) nil) (let (start end ext-start) (dolist (pair ls) (setq start (car pair) end (cdr pair)) ;; This is a bit of a hack. Leaving out the white space ;; stops the field text from occassionally taking on the ;; 'db-inter-field-face'. If the user did not use white ;; space the this would evidently not work. (goto-char start) (skip-chars-forward " \t\n") (setq ext-start (point)) (goto-char end) (skip-chars-backward " \t\n") (when (< ext-start (point)) (set-extent-face (make-extent ext-start (point)) 'db-inter-field-face)))))))) ;; ;; formerly in db-interfa.el ;; (define-key database-view-mode-map [mouse1] 'db-lucid-mouse-jump-to-point) (define-key database-view-mode-map [mouse3] 'database-view-mode-menu) (define-key database-edit-mode-map [mouse1] 'db-lucid-mouse-jump-to-point) (define-key database-edit-mode-map [mouse3] 'database-edit-mode-menu) (define-key database-summary-mode-map [mouse1] 'db-lucid-mouse-jump-to-point) (defun db-lucid-mouse-jump-to-point (e) "Move to the field or record nearest the mouse position. See `db-jump-to-point' for more details." (interactive "@e") ; @ = select buffer, e = event (mouse-track e) ; set point to where the mouse is (db-jump-to-point)) (defun dbs-lucid-mouse-view (e) "Visit record under mouse in Database View mode." (interactive "@e") (mouse-set-point e) (db-jump-to-point) (dbs-view)) ;; ;; formerly in db-summary.el ;; (require 'mode-motion) (add-hook 'database-summary-mode-hooks (lambda () (setq mode-motion-hook 'mode-motion-highlight-line))) ;; (db-lucid-summary-mode-menubar) (define-key database-summary-mode-map [mouse1] 'db-lucid-mouse-jump-to-point) (define-key database-summary-mode-map [mouse2] 'dbs-lucid-mouse-view) (define-key database-summary-mode-map [mouse3] 'database-summary-mode-menu) ;;; db-lemacs.el ends here edb-1.31/lisp/db-nosetf.el0000444000175000017500000000634010745616666013560 0ustar ttnttn;;; db-nosetf.el --- EDB programming interface that does not use setf ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Internally, EDB uses `defstruct' which normally provides for each slot a ;; TYPE-SLOT function which is setf-able. Thus: ;; ;; (TYPE-SLOT object) ; getter ;; (setf (TYPE-SLOT object) value) ; setter ;; ;; EDB 1.x defines aliases for the setter of the form: ;; ;; (TYPE-set-SLOT object value) ;; ;; This file provides all those aliases, which although unused internally, ;; are documented in the EDB Manual, and will continue to be supported for ;; the 1.x series. 2.x is another matter, however... ;;; Code: (defsubst database-set-print-name (db val) (setf (database-print-name db) val)) (defsubst database-set-fieldnames (db val) (setf (database-fieldnames db) val)) (defsubst database-set-recordfieldspecs (db val) (setf (database-recordfieldspecs db) val)) (defsubst database-set-field-priorities (db val) (setf (database-field-priorities db) val)) (defsubst database-set-read-record-from-region (db val) (setf (database-read-record-from-region db) val)) (defsubst database-set-write-region-from-record (db val) (setf (database-write-region-from-record db) val)) (defsubst database-set-sub-fieldsep-string (db val) (setf (database-sub-fieldsep-string db) val)) (defsubst database-set-sub-recordsep-string (db val) (setf (database-sub-recordsep-string db) val)) (defsubst database-set-substitutions (db val) (setf (database-substitutions db) val)) (defsubst database-set-locals (db val) (setf (database-locals db) val)) (defsubst sepinfo-set-pre-first-string (si val) (setf (sepinfo-pre-first-string si) val)) (defsubst sepinfo-set-pre-first-regexp (si val) (setf (sepinfo-pre-first-regexp si) val)) (defsubst sepinfo-set-pre-first-regexp-submatch (si val) (setf (sepinfo-pre-first-regexp-submatch si) val)) (defsubst sepinfo-set-sep-string (si val) (setf (sepinfo-sep-string si) val)) (defsubst sepinfo-set-sep-regexp (si val) (setf (sepinfo-sep-regexp si) val)) (defsubst sepinfo-set-sep-regexp-submatch (si val) (setf (sepinfo-sep-regexp-submatch si) val)) (defsubst sepinfo-set-sep-function (si val) (setf (sepinfo-sep-function si) val)) (defsubst sepinfo-set-post-last-string (si val) (setf (sepinfo-post-last-string si) val)) (defsubst sepinfo-set-post-last-regexp (si val) (setf (sepinfo-post-last-regexp si) val)) (defsubst sepinfo-set-post-last-regexp-submatch (si val) (setf (sepinfo-post-last-regexp-submatch si) val)) (provide 'db-nosetf) ;;; db-nosetf.el ends here edb-1.31/lisp/db-oldnames.el0000444000175000017500000001507510745616666014071 0ustar ttnttn;;; db-oldnames.el --- map old names to new funcs/vars if possible ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Usage: (require 'db-oldnames) ;; ;; This is for EDB 1.x support; it will NOT be available w/ EDB 2.x. ;; ;; If you find yourself using a function or variable named in this file, ;; it's probably a good idea to replace it w/ the newer name so as to be ;; able to avoid loading this file in the first place. ;;; Code: (defalias 'define-alternative-multi-char-displaytype 'define-enum-type) (defalias 'string-lessp-ci 'db-string-lessp-ci) (defalias 'string-order-ci 'db-string-order-ci) (defalias 'make-regexp-pattern 'db-make-regexp-pattern) (defalias 'regexp-pattern-regexp 'db-regexp-pattern-regexp) (defalias 'make-string-pattern 'db-make-string-pattern) (defalias 'string-pattern-regexp 'db-string-pattern-regexp) (defalias 'string-pattern-string 'db-string-pattern-string) (defalias 'string-match-function 'db-string-match-function) (defalias 'string-match-display->actual 'db-string-match-display->actual) (defalias 'string-match-actual->display 'db-string-match-actual->display) (defalias 'string-or-nil->string 'db-string-or-nil->string) (defalias 'string-or-nil-lessp-ci 'db-string-or-nil-lessp-ci) (defalias 'string-or-nil-order-ci 'db-string-or-nil-order-ci) (defalias 'string-or-nil-match-function 'db-string-or-nil-match-function) (defalias 'string->nil-or-string 'db-string->nil-or-string) (defalias 'make-n-line-sep-function 'db-make-n-line-sep-function) (require 'edb-t-human-names) (defalias 'order-last-names 'edb-t-human-names:order-last-names) (defalias 'canonicalize-name 'edb-t-human-names:canonicalize-name) (defalias 'same-first-name-p 'edb-t-human-names:same-first-name-p) (defalias 'order-first-names 'edb-t-human-names:order-first-names) (defalias 'nicknamep 'edb-t-human-names:nicknamep) (defalias 'standardize-name 'edb-t-human-names:standardize-name) (defalias 'name->name-jr 'edb-t-human-names:name->name-jr) (defalias 'name->first-last-jr 'edb-t-human-names:name->first-last-jr) (require 'edb-t-places-usuk) (defalias 'postal-code-p 'edb-t-places-usuk:postal-code-p) (defalias 'statep 'edb-t-places-usuk:statep) (defalias 'full-state-name 'edb-t-places-usuk:full-state-name) (defalias 'abbreviate-state 'edb-t-places-usuk:abbreviate-state) (require 'edb-t-timedate1) (defalias 'make-date 'edb-t-timedate1:make-date) (defalias 'date-year 'edb-t-timedate1:date-year) (defalias 'date-month 'edb-t-timedate1:date-month) (defalias 'date-day 'edb-t-timedate1:date-day) (defalias 'make-empty-date 'edb-t-timedate1:make-empty-date) (defalias 'date-year-long 'edb-t-timedate1:date-year-long) (defalias 'date->day-of-year 'edb-t-timedate1:date->day-of-year) (defalias 'date->absolute-days 'edb-t-timedate1:date->absolute-days) (defalias 'date->weekday-index 'edb-t-timedate1:date->weekday-index) (defalias 'date->weekday-name 'edb-t-timedate1:date->weekday-name) (defalias 'date-order-absolute 'edb-t-timedate1:date-order-absolute) (defalias 'parse-date-string 'edb-t-timedate1:parse-date-string) (defalias 'parse-date-string-or-nil 'edb-t-timedate1:parse-date-string-or-nil) (defalias 'parse-date-default-function 'edb-t-timedate1:parse-date-default-function) (defalias 'format-date 'edb-t-timedate1:format-date) (defalias 'simple-format-date 'edb-t-timedate1:simple-format-date) (defalias 'simple-format-date-or-nil 'edb-t-timedate1:simple-format-date-or-nil) (defalias 'format-date-mmddyy 'edb-t-timedate1:format-date-mmddyy) (defalias 'format-date-ddmmyy 'edb-t-timedate1:format-date-ddmmyy) (defalias 'format-date-yymmdd 'edb-t-timedate1:format-date-yymmdd) (defalias 'format-date-ddmmmyy 'edb-t-timedate1:format-date-ddmmmyy) (defalias 'format-date-yyyymmdd 'edb-t-timedate1:format-date-yyyymmdd) (defalias 'format-date-full 'edb-t-timedate1:format-date-full) (defalias 'format-date-unix 'edb-t-timedate1:format-date-unix) (defalias 'format-date-all 'edb-t-timedate1:format-date-all) (defalias 'format-date-dec 'edb-t-timedate1:format-date-dec) (defalias 'format-date-europe 'edb-t-timedate1:format-date-europe) (defalias 'date-match-function 'edb-t-timedate1:date-match-function) (defalias 'date-merge 'edb-t-timedate1:date-merge) (defalias 'date->storage-string-mmddyyyy 'edb-t-timedate1:date->storage-string-mmddyyyy) (defalias 'storage-string-mmddyyyy->date 'edb-t-timedate1:storage-string-mmddyyyy->date) (defalias 'date->storage-string-lisp 'edb-t-timedate1:date->storage-string-lisp) (defalias 'storage-string-lisp->date 'edb-t-timedate1:storage-string-lisp->date) (defalias 'date-stored->actual 'edb-t-timedate1:date-stored->actual) (defalias 'make-time 'edb-t-timedate1:make-time) (defalias 'time-hours 'edb-t-timedate1:time-hours) (defalias 'time-mins 'edb-t-timedate1:time-mins) (defalias 'time-secs 'edb-t-timedate1:time-secs) (defalias 'make-empty-time 'edb-t-timedate1:make-empty-time) (defalias 'empty-time-p 'edb-t-timedate1:empty-time-p) (defalias 'time-default-constraint 'edb-t-timedate1:time-default-constraint) (defalias 'parse-time-string 'edb-t-timedate1:parse-time-string) (defalias 'parse-time-default-function 'edb-t-timedate1:parse-time-default-function) (defalias 'format-time-24 'edb-t-timedate1:format-time-24) (defalias 'format-time-12 'edb-t-timedate1:format-time-12) (defalias 'format-time-12-hhmm 'edb-t-timedate1:format-time-12-hhmm) (defalias 'format-time-24-hhmm 'edb-t-timedate1:format-time-24-hhmm) (defalias 'time-order 'edb-t-timedate1:time-order) (defalias 'time-match-function 'edb-t-timedate1:time-match-function) (defalias 'time->storage-string 'edb-t-timedate1:time->storage-string) (defalias 'storage-string->time 'edb-t-timedate1:storage-string->time) (defalias 'time-merge 'edb-t-timedate1:time-merge) (defalias 'date->storage-string 'edb-t-timedate1:format-date-full) (defalias 'storage-string->date 'edb-t-timedate1:date-stored->actual) (defalias 'format-time-hhmm 'edb-t-timedate1:format-time-12-hhmm) (provide 'db-oldnames) ;;; db-oldnames.el ends here edb-1.31/lisp/db-rdb.el0000444000175000017500000004734410745616666013042 0ustar ttnttn;;; db-rdb.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Provide support for RDB files, which can be a special case of a tagged ;; file, or, a tabular-format file. ;; ;; The RDB header for both kinds of files contains the field names and ;; the field descriptors, which are its length, type, and a "help" string. ;; ;; There are Perl scripts (by Walter Hobbs) implementing RDB files, and this ;; file is an attempt to provide EDB access to these kinds of files. ;; This file began as a copy of db-tagged.el, but has since been almost ;; completely rewritten. ;; The basic way to use this is to call "db-rdb-setup" with a list ;; describing the fields. The purpose of the fields is to provide the ;; Elisp programmer a handle on the external fields. The usage is ;; documented in the function. ;;; Code: (require 'database) (eval-when-compile (require 'cl)) (eval-when-compile (defvar database)) ; used dynamically ;;; Functions ;;; Abstraction of the RDB field specification: (HANDLE TAG HELP) ;;; HANDLE --> (NAME . TAG) or NAME (defsubst db-rdb-fspec-handle (fspec) (car fspec)) (defsubst db-rdb-fspec-name (fspec) (if (consp (car fspec)) (car (car fspec)) (car fspec))) (defsubst db-rdb-fspec-type (fspec) (if (consp (car fspec)) (cdr (car fspec)))) (defsubst db-rdb-fspec-tag (fspec) (car (cdr fspec))) (defsubst db-rdb-fspec-help (fspec) (car (cdr (cdr fspec)))) ;;;###autoload (defun db-rdb-setup (rfspecs &optional lock-flag) "Ready the database to read files in RDB format. Creates database local variables and sets database slots. Argument RFSPECS is a list of rdb-field specifications, one for each field in a database record. Optional, second argument LOCK-FLAG should be non-nil to lock the file for synchronized updates. The locking and unlocking is done with \"rdblock\" and \"rdbunlock\", which must be available in the current PATH environment variable. Each field specification is a three-element list of the field name \(a symbol\), the tag used to identify it in the file \(a string\), and a brief help string. Instead of a symbol, the rdb-field name may be a two-element list of the field name its type. To indicate that a field is never found in the input file \(typically because it is computed on the fly\), use nil for its tag." (let ((details (edb--1D database :rdb-details)) (defaults (list :file-type 'list :list-entry-regexp (concat "[ \t]*\\([" "a-zA-Z0-9_" "]*\\)" (regexp-quote " | ") "[ \t]*") :list-continuation-regexp "^[ \t]*|[ \t]+" :list-continuation-output nil :max-field-name-length 0 :continuation-output nil))) ;; First, try to detect whether this database was once in RDB file ;; layout, but is now in internal file layout. (if details (unless (gethash :converted-p details) (puthash :converted-p t details)) (apply 'edb--mputhash (setq details (edb--1D! database :rdb-details (make-hash-table :test 'eq :size 19))) :rdb-field-defs rfspecs defaults) (let* ((db database) (rsi (database-record-sepinfo db)) (efields (db-rdb-read-fields db)) (fspecs (db-rdb-correlate-field-defs rfspecs efields)) (len 0)) (cond ;; table format ((eq 'table (gethash :file-type details)) ;; table style is the same a regular file layout (error "db-rdb-setup: table format not implemented yet!")) ;; list format ((eq 'list (gethash :file-type details)) ;; discover the maximum of the length of all the field tags (mapc (lambda (fld) (let ((tag (db-rdb-fspec-tag fld))) (when (> (length tag) len) (setq len (length tag))))) fspecs) (edb--mputhash details :max-field-name-length len :continuation-output (concat (make-string len 32) " | ")) (setf (database-read-record-from-region db) 'db-rdb-list-rrfr (database-write-region-from-record db) 'db-rdb-list-wrfr ;; set pre-first-regexp to remove the header, up to the ;; first pair of newlines (sepinfo-pre-first-regexp rsi) (concat "\\`\\(" "\\([^\n]\\|\n[^\n]\\)*" "\n\n\\)") (sepinfo-pre-first-regexp-submatch rsi) 1 (sepinfo-sep-string rsi) "\n\n" (sepinfo-post-last-string rsi) "\n" ;; Save the header as the pre-first-string so it will get ;; written back on output. At some point, maybe we should allow ;; for dynamic changes to the field definitions. (sepinfo-pre-first-string rsi) (gethash :header-string details)))) ;; tell EDB about the fields now (database-set-fieldnames-to-list db (mapcar 'db-rdb-fspec-handle fspecs) ;; Most fields are strings (or missing, here represented as nil) 'nil-or-string) ;; Save help strings. (let* ((ls (mapcar 'db-rdb-fspec-help fspecs)) (walk ls) (fno 0)) (while walk (setcdr walk (cons (car walk) (cdr walk))) (setcar walk fno) (incf fno) (setq walk (cddr walk))) (apply 'db-set-field-help database ls)) ;; Elaborate recordfieldspecs. FIXME: This should not be necessary. (let* ((all-rs (database-recordfieldspecs database)) (count (length all-rs))) (do ((fno 0 (1+ fno))) ((= fno count)) (aset all-rs fno (db-rfspec<-rftype (aref all-rs fno))))) (add-hook 'db-after-read-hooks 'db-rdb-database-stored->actual))))) (defun db-rdb-database-stored->actual (&optional db) "Like `database-stored->actual', but only in RDB file layout." (let ((details (edb--1D db :rdb-details))) (when (and details (not (gethash :converted-p details))) (database-stored->actual db) (puthash :converted-p t details)))) ;; Read RDB List format region record (defun db-rdb-list-rrfr () "With the current buffer narrowed to a single RDB List record, parse it into field values." (let* ((db database) (details (edb--1D db :rdb-details)) (srx "^[ \t]*\\([a-zA-Z0-9_]*\\)[ \t]*|[ \t]*") (crx "^[ \t]*|[ \t]*") tag fld old val pl) ;; run-hooks takes a SYMBOL as its argument (let ((prep (gethash :pre-parse-thunk details))) (if prep (funcall prep) ;; todo: zonk after EDB 1.27 (run-hooks 'db-rdb-rrfr-hooks))) (goto-char (point-min)) (while (not (eobp)) (unless (looking-at srx) (error "This didn't look right to me (point = %d)" (point))) (setq tag (match-string 1) fld (let ((fields (gethash :rdb-field-defs details)) (sym nil)) (dolist (field fields) (when (equal tag (car (cdr field))) (setq sym (car field)))) (if sym ; found it? (when (consp sym) ; is it a node? (setq sym (car sym))) ; return just the symbol ;; Field not defined -- report it, then add it (message "Field name % encountered, but not defined." tag) (setq fields (gethash :rdb-field-defs details)) (nconc fields (list (list (cons (setq sym (intern tag)) 'string-or-nil) tag "Undefined field")))) sym) old (plist-get pl fld)) (end-of-line) (setq val (buffer-substring (match-end 0) (point))) ;; Why isn't this (forward-char 1)? (forward-line 1) (while (looking-at crx) (end-of-line) (setq val (concat val "\n" (buffer-substring (match-end 0) (point)))) (forward-line 1)) (push (if old (concat old "\n" val) val) pl) (push fld pl)) pl)) ;; RDB write RDB List file record from database record (defun db-rdb-list-wrfr (record) "Given an EDB RECORD, write convert to the RDB List format representation and write to the file." (let* ((db database) (a->s-slice (db-rs-slice db 'edb--1rs-actual->stored)) (nm2no (edb--1D db :nm2no)) (details (edb--1D db :rdb-details)) (len (gethash :max-field-name-length details)) (contin (gethash :continuation-output details))) ;; run-hooks takes a SYMBOL as its argument (let ((prep (gethash :pre-write-function details))) (if prep (funcall prep record) ;; todo: zonk after EDB 1.27 (run-hooks 'db-rdb-wrfr-before-hooks))) (mapc (lambda (def) (let ((nam (db-rdb-fspec-name def)) (tag (db-rdb-fspec-tag def))) (unless (null tag) ;; Fields without tags are computed, so don't get stored (let* ((fno (gethash nam nm2no)) (a->s (aref a->s-slice fno)) (val (let ((v (aref record fno))) (if a->s (funcall a->s v) v)))) ;; null or empty values don't get written (unless (or (null val) (equal "" val)) (let ((pad (- len (length tag))) (i 0) j) ;; right-align the RDB field names (when (> pad 0) (insert (make-string pad 32))) (insert tag " | ") (while (setq j (string-match "\n" val i)) (insert (substring val i j) "\n" contin) (setq i (+ j 1))) (insert (substring val i) "\n"))))))) (gethash :rdb-field-defs details)) ;; HACK: punt last newline, it'll be added back later (delete-char -1) (let ((post (gethash :post-write-function details))) (if post (funcall post record) (run-hooks 'db-rdb-wrfr-after-hooks))))) (defun db-rdb-read-fields (db) "In DATABASE, read the RDB-style headers, creating a list of field definitions, which is returned as the result." "Setup the field names from the current EDB database file, which is assumed to be formatted as an RDB database. The RDB database may be either in List format or Table form. Any updates will continue to maintain the RDB file in its current form. Any EDB format files for the database will be used automatically. The argument, FIELDDEFS, is a list of elements: \(\(SYMBOL FIELD-NAME FIELD-HELP\)...\). SYMBOL may itself be either an atom, a symbol, or a cons cell of \(SYMBOL . TYPE\). SYMBOL is used to identify the field by name in elisp code. TYPE, if given, must be a valid EDB fieldtype, either preconfigured, or user-defined. If TYPE is null or hidden, it will be deduced from the corresponding RDB header, utimately defaulting to \"string\". The FIELD-NAME is a string which must match one of the corresponding field names in the database. FIELD-NAMES which do not exist in the RDB file are shown in an error message, as are any unmentioned field names read from the RDB header. The FIELD-HELP is a string used for information when queried with \"?\" interactively. If FIELD-HELP is null, any comment in the field definition from the RDB file is used instead. Lastly, if FIELDDEFS is null, then all of the information will be obtained entirely from the RDB file, with the SYMBOL defaulting to the symbol with the same print-string as FIELD-NAME." (with-current-buffer db-buffer (goto-char (point-min)) (while (looking-at "^#") (forward-line 1)) ;; if the first non-comment line is empty, we're in List mode (if (looking-at "^[ \t]*\n") ;; Positioned at the blank line preceeding the field definitions in an ;; RDB List file, read the field definitions and return them as an ;; association list: ((FIELD-NAME FIELD-DEF FIELD-HELP)...). (let (fields name defn width help end) (forward-line 1) ; go to the first real line (while (not (looking-at "^[ \t]*$")) (cond ((looking-at "^\#")) ; ignore comments ((looking-at "^[ \t]*\\(\\w+\\)[ \t]+|[ \t]+\\(.*\\)$") (setq name (match-string 1) defn (db-string-split-first-word (match-string 2)) help (car-safe (cdr-safe defn)) defn (car defn) width (and (string-match "\\([0-9]+\\)" defn) (string-to-number (match-string 1 defn))) defn (and (string-match "\\([SNDM<>]\\)" defn) (match-string 1 defn)) fields (append fields (list (list name width defn help)))))) (forward-line 1)) ;; we're just past the header -- copy everything and save it in ;; a local variable, so our caller can stuff into a record sepinfo. (forward-line 1) ; skip the header/record separator (edb--mputhash (edb--1D database :rdb-details) :header-string (buffer-substring (point-min) (point)) :header-fields fields ;; leave some clues as to the kind of RDB file we've parsed :file-type 'list) ;; return with the fields fields) ;; Positioned at the field name line in an RDB Table file, read the ;; field definitions and setup EDB for regular-file format. Leave the ;; buffer positioned before the first record, if any. (let ((db database)) (error "Not implemented yet.") (puthash :file-type 'table (edb--1D db :rdb-details)))))) (defun db-rdb-correlate-field-defs (ifields efields) "Given INTERNAL-FIELDS and EXTERNAL-FIELDS, correlate the fields with each other and produce a field list suitable for M-x db-rdb-setup. INTERNAL-FIELDS is a list: \(\(HANDLE NAME HELP\)...\), where HANDLE is either \(SYMBOL . TYPE\) or just SYMBOL. EXTERNAL-FIELDS is a list: \(\(NAME WIDTH FORMAT HELP\)...\), produced by the function rdb-read-field-defs. If TYPE is hidden, it is deduced from the corresponding FORMAT. Similarly, if the internal HELP is hidden, any external HELP is used. The internal definition always overrides the external, since it is more specific to the EDB implementation. The resulting list format is: \(\(\(SYMBOL . TYPE\) NAME HELP\)...\)." (let ((errs 0) fieldspec inames) (when (null ifields) (setq ifields (mapcar (lambda (edef) ; make default be same names (list (intern (car edef)))) efields))) ;; now correlate internal fields with the external fields ;; while we're mapping over the idefs, build an alist of names ;; to use later for the reverse correlation check. (setq fieldspec (mapcar (lambda (idef) (let* ((handle (nth 0 idef)) (name (nth 1 idef)) ; field name (tag) (ihelp (nth 2 idef)) (symbol (or (and (atom handle) handle) (car handle))) (type (and (consp handle) (cdr handle))) (edef (and name (assoc name efields))) width format ehelp) (setq inames (append inames (list (list name)))) (if (and name (not edef)) (progn (message "Internal field `%s' %s" name "not externally defined") (beep t) (sit-for 3) (incf errs)) ;; else name could be null because it's dynamic (when edef (setq width (nth 1 edef) format (nth 2 edef) ehelp (nth 3 edef)))) ;; do merge of field info and return: ;; ( (SYMBOL . TYPE) NAME HELP ) (list (cons symbol (or type (cond ;; left-aligned string ((or (null format) (equal format "S") (equal format "<")) 'one-line-string) ;; fixme: turn on right-alignment in ;; associated field displayspec --ttn ((equal format ">") 'one-line-string) ((equal format "N") 'integer-or-nil) ;; dates ((or (equal format "D") (equal format "M")) 'date-mmddyy) ;; no other alternatives ;; an error report (t (message "Unknown field format: %S, %s" format "string assumed") (beep t) (sit-for 3) 'one-line-string)))) name (or ihelp ehelp)))) ifields)) ;; Now make sure we got all the external fields named ;; using the inames alist we built in the mapcar above. (mapc (lambda (edef) (let* ((name (nth 0 edef)) (idef (assoc name inames))) (unless idef (message "External field %s not defined internally" name) (sit-for 3) (incf errs)))) efields) (unless (zerop errs) (unless (y-or-n-p (format "%d errors occurred; continue? " errs)) (error "db-rdb-setup: %d errors" errs))) fieldspec)) ;;;--------------------------------------------------------------------------- (provide 'db-rdb) ;;; db-rdb.el ends here edb-1.31/lisp/db-rep.el0000444000175000017500000005077410745616666013062 0ustar ttnttn;;; db-rep.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Representation and basic operations for ;; database, recordfieldspec objects. ;;; Code: (:edb1 :1singles (make-hash-table :test 'eq :weakness 'key)) (edb--define-child-hash 1D db (edb--G :1singles) (let ((new (make-hash-table :size 7))) (flet ((ahash () (make-hash-table :test 'eq :weakness 'key))) (edb--mputhash new :markedp (ahash) :hiddenp (ahash)) new))) (defun edb--1all-known-databases () (edb--hashcollect :keys (edb--G :1singles))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Database abstraction ;;; (put 'edb :databases-made 0) (defstruct (edb--v1-monolithic-mess (:type vector) (:constructor edb--make-v1-monolithic-mess) (:conc-name database-) (:copier edb--copy-v1-monolithic-mess)) (print-name (format "Unnamed Database %d" (incf (get 'edb :databases-made)))) ;; field information fieldnames ; this is repeated in the recordpsecs recordfieldspecs ; vector: symbols or recordfieldspecs ; if symbol, search :1recordfieldtypes field-priorities ; maybe call this order-fields instead ;; For file i/o (record-sepinfo (edb--make-v1-sepinfo) :read-only t) (field-sepinfo (edb--make-v1-sepinfo) :read-only t) read-record-from-region write-region-from-record sub-fieldsep-string sub-recordsep-string substitutions ; associate ACTUAL with STORED strings locals ; associate SYMBOL with VALUE ) ;;; Accessors (defun database-set-modified-p (db val) (unless (eq val (edb--1D db :modp)) (edb--1D! db :modp val) ;; Reflect the change in each data display buffer. (mapc (lambda (ddb) (with-current-buffer ddb (set-buffer-modified-p val) (force-mode-line-update))) (edb--1D db :ddbufs)))) (defun database-file (db) ;; EDB 1.x compatability; will NOT be available in EDB 2.x. (edb--1D db :file)) (defun database-data-display-buffers (db) ;; EDB 1.x compatability; will NOT be available in EDB 2.x. (edb--1D db :ddbufs)) (defun database-no-of-records (db) ;; EDB 1.x compatability; will NOT be available in EDB 2.x. (edb--1D db :nrecords)) ;;; Non-primitive accessors (defun db-rs-slice (db which) (let ((rs-slices (edb--1D db :rs-slices))) (or (gethash which rs-slices) (puthash which (let* ((all-rs (edb--1D db :elaborated-rfspecs)) (len (length all-rs)) (v (make-vector len nil))) (do ((i 0 (1+ i))) ((= len i)) (aset v i (funcall which (aref all-rs i)))) v) rs-slices)))) ;;; Database-local variables (defun database-make-local (symbol db &optional value) "Declare a database-local variable named by SYMBOL for DATABASE. Each such variable should only be declared once. If optional argument VALUE is specified, the variable is set to it." (let ((lookup (assq symbol (database-locals db)))) (if lookup (error "%s is already defined as a local variable in %s." symbol (database-print-name db)) (push (cons symbol value) (database-locals db))))) (defun database-set-local (symbol db value &optional no-error) "Set the value of database-local variable SYMBOL, in DB, to VALUE. SYMBOL must have been declared by a previous call to `database-make-local' unless optional argument NO-ERROR is supplied, in which case the function does that automatically, if necessary." (let ((lookup (assq symbol (database-locals db)))) (if lookup (setcdr lookup value) (if no-error (database-make-local symbol db value) (error "%s is not a database-local variable for %s." symbol (database-print-name db)))))) (defun database-get-local (symbol db &optional no-error) "Return the value of database-local variable SYMBOL for DATABASE. If SYMBOL was not declared by a previous call to `database-make-local', an error is signalled unless optional argument NO-ERROR is non-nil, in which case nil is returned." (let ((lookup (assq symbol (database-locals db)))) (cond (lookup (cdr lookup)) (no-error nil) (t (error "%s is not a database-local variable for %s." symbol (database-print-name db)))))) (defun database-local-p (symbol db) "Return non-nil if SYMBOL is a database-local variable for DATABASE." (assq symbol (database-locals db))) ;;; Non-primitive setters (eval-when-compile (defvar db-default-field-type)) (defun database-set-fieldnames-to-list (db fspecs &optional dtype) "Set DB's fieldnames and record field types according to FSPECS. But do nothing if DB's `fieldnames' slot is already set. FSPECS is a list, each element of which can either be a single symbol, the field name, or a cons (NAME . RECORDFIELDTPYE). Optional third arg DTYPE specifies the default recordfieldtype for single-symbol elements. If DTYPE is not given, use the value of `db-default-field-type' (NOTE: this variable is deprecated) if bound, or `string' otherwise." (unless (database-fieldnames db) (let* ((len (length fspecs)) (fno 0) (rs (make-vector len nil)) (vec (make-vector len nil)) (n2n (make-hash-table :size len :test 'eq)) ;; We used to use a buffer-local var `db-default-field-type', but ;; that was a bug; a field's type is a property of the field, not ;; of its display, not of a buffer. Generally, the concepts of ;; "local" and "default" together are difficult to explain w/o ;; detailed knowledge of the implementation and its precise timing ;; of events. Better to specify the default together with the ;; non-defaults, such as is now possible w/ DTYPE, and let this ;; function worry about making the correct associations. ;; ;; For EDB 1.x, although we are obligated to check for use of this ;; var, we are free to drop the buffer-local var, as long as we ;; explain ourselves clearly in the documentation. (default-type (cond (dtype) ((and (boundp 'db-default-field-type) db-default-field-type)) (t 'string)))) (dolist (fname fspecs) (let ((type (if (consp fname) (prog1 (cdr fname) (setq fname (car fname))) default-type))) (if (gethash type (edb--G :1recordfieldtypes)) (aset rs fno type) (error "bad type %s" type)) (aset vec fno fname) (puthash fname fno n2n) (incf fno))) (edb--1D! db :nm2no n2n) ;; elaborate (let ((elab (copy-sequence rs)) one-rs) (do ((fno 0 (1+ fno))) ((= len fno)) (when (symbolp (setq one-rs (aref elab fno))) (aset elab fno (db-rfspec<-rftype one-rs)))) (edb--1D! db :elaborated-rfspecs elab)) (edb--1D! db :rs-slices (make-hash-table :size 5 :test 'eq)) (setf (database-fieldnames db) vec (database-recordfieldspecs db) rs)))) ;;; Not quite so basic functions. (defun database-full-fieldsep-string (db) ;; Return the string that really separates database record fields. (if (database-write-region-from-record db) nil (sepinfo-sep-string (database-field-sepinfo db)))) (defun database-full-recordsep-string (db) ;; Return the string that really separates database records. (let ((rsep (database-record-sepinfo db))) (if (database-write-region-from-record db) (sepinfo-sep-string rsep) (let ((fsep (database-field-sepinfo db))) (concat (sepinfo-post-last-string fsep) (sepinfo-sep-string rsep) (sepinfo-pre-first-string fsep)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Recordfieldspec abstraction ;;; (defstruct (edb--v1-rs (:type vector) :named (:constructor edb--make-v1-rs) (:conc-name edb--1rs-) (:copier edb--copy-v1-rs)) ;; datatype information type ; e.g. 'string default-value common-form-function merge-function order-fn ; (A B) => {-1,0,1} sort-fn ; (A B) => bool match-function ; (PATTERN OBJ) => bool help-info ; perhaps should be help-string; ; or should be more complicated. actual->stored stored->actual ;; customizations constraint-function) (put 'edb--v1-rs 'kwidx ; poor man's defsetf --ttn (let ((idx 0)) (mapcar (lambda (ent) (cons (intern (format ":%s" (symbol-name (car ent)))) (incf idx))) (cdr (get 'edb--v1-rs 'cl-struct-slots))))) (defun db-rs-sortfunc (rs &optional reversep) "Return a sort function for records described by recordfieldspec RS. If optional argument REVERSEP is non-nil, then the sort function goes in the opposite order. If the sort-fn slot of the appropriate recordfieldspec of `database' doesn't contain one, one is made up on the fly from the order-fn slot. If the order-fn slot is also empty, the resulting function always returns nil, indicating that it is not the case that the first argument is less than the second." (let ((sort-fn (edb--1rs-sort-fn rs))) (if sort-fn (if reversep `(lambda (value1 value2) ;; Maintain arg order and invert the result, so as ;; to properly handle the case: (eq value1 value2). (not (,sort-fn value1 value2))) sort-fn) (let ((order-fn (edb--1rs-order-fn rs))) (if order-fn `(lambda ,(if reversep '(value2 value1) '(value1 value2)) (= -1 (funcall (function ,order-fn) value1 value2))) 'nil-function))))) (defun db-rs-ordfunc (rs &optional reversep) "Return an order function for records described by recordfieldspec RS. If optional argument REVERSEP is non-nil, then the order function goes in the opposite order. If the order-fn slot of the appropriate recordfieldspec of `database' doesn't contain one, one is made up on the fly from the sort-fn slot; `equal' is used to determine whether two records are equal. If the sort-fn slot is also empty, the resulting function always returns 0, indicating equality." (let ((order-fn (edb--1rs-order-fn rs))) (if order-fn (if reversep `(lambda (value1 value2) (,order-fn value2 value1)) order-fn) (let ((sort-fn (edb--1rs-sort-fn rs))) (if sort-fn `(lambda ,(if reversep '(value2 value1) '(value1 value2)) (cond ((equal value1 value2) 0) ((funcall (function ,sort-fn) value1 value2) -1) (t 1))) (lambda (value1 value2) 0)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Records ;;; ;; Abstraction (defun db--mkrec (nfields nm2no init) (let ((rv (make-vector nfields nil))) (cond ((eq :alist (car init)) ; alist (dolist (pair (cdr init)) (aset rv (gethash (car pair) nm2no) (cdr pair)))) (t ; plist (while init (aset rv (gethash (pop init) nm2no) (pop init))))) rv)) (defun db-make-record (database init) "Return a DATABASE-specific record initialized with INIT. INIT is either a list of alternating fieldnames (symbols) and values, or a list whose car is the keyword `:alist' and whose cdr is an alist mapping fieldnames to their values." (db--mkrec (length (database-fieldnames database)) (edb--1D database :nm2no) init)) (defun db-copy-r2r (source target) "Copy the field values of the SOURCE record to the TARGET record." (dotimes (fno (length source)) (aset target fno (aref source fno)))) ;;; Fieldnames and record fieldnumbers (defsubst db-fname<-fno (fieldnumber db) "Given a record FIELDNUMBER and DB, return a record fieldname." (aref (database-fieldnames db) fieldnumber)) ;;; Retrieving field values (defun db-record-field (record fieldname &optional database) "Return from RECORD the field with name FIELDNAME. If RECORD is t, use the \"current record\". Optional third argument DATABASE specifies a database other than the current one." (let* ((db (or database dbc-database)) (fno (or (gethash fieldname (edb--1D db :nm2no)) (error "No %s field in current record." fieldname))) (rec (if (eq t record) (edb--S :under) record))) (aref rec fno))) ;;; Checking constraints (defun db-check-constraint (value rec idx db) (let ((func (aref (db-rs-slice db 'edb--1rs-constraint-function) idx))) (when (and func (not (funcall func value rec idx db))) (error "The value `%s' does not satisfy the constraint for field %s." value (db-fname<-fno idx db))))) ;;; Setting field values (defun db-record-set-field (record fieldname value &optional database nocheck) "Set, in RECORD, field FIELDNAME to VALUE. Fourth argument is DATABASE. Check constraints first unless optional fifth argument NOCHECK is non-nil." (let* ((db (or database dbc-database)) (fno (or (gethash fieldname (edb--1D db :nm2no)) (error "No %s field in current record." fieldname)))) (unless (or nocheck (not db)) (db-check-constraint value record fno db)) (aset record fno value))) ;;; Setting fields in :under (defsubst dbf-this-record-set-field (fieldname value) "Set field with name FIELDNAME in `:under' to VALUE. Causes the entire record to be redisplayed pretty soon. You may want to use `dbf-displayed-record-set-field' instead." ;; fixme: check `(edb--S :utkmodp)' first. --ttn (db-record-set-field (edb--S :under) fieldname value) (setq dbf-redisplay-entire-record-p t)) ;;; The displayed record (defsubst dbf-displayed-record-field (fieldname) "Return the value of the field named FIELDNAME from the displayed record." (db-record-field (dbf-displayed-record) fieldname)) (defun dbf-displayed-record-set-field (fieldname value) "Set field with name FIELDNAME in displayed record to VALUE. Cause the entire record to be redisplayed soon." ;; Make sure displayed-record = this-record. (dbf-set-this-record-modified-p t) (dbf-this-record-set-field fieldname value)) (defsubst dbf-displayed-record-set-field-and-redisplay (fieldname value) "Set field with name FIELDNAME in displayed record to VALUE. Cause the entire record to be redisplayed immediately." ;; Is this correct? Maybe displayed-record != this-record. (dbf-this-record-set-field fieldname value) (dbf-redisplay-entire-record-maybe)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Sepinfo abstraction ;;; ;; This tells how a list of information appears in a file. (defstruct (edb--v1-sepinfo (:type vector) (:constructor edb--make-v1-sepinfo) (:conc-name sepinfo-)) pre-first-string pre-first-regexp pre-first-regexp-submatch sep-string sep-regexp sep-regexp-submatch sep-function ; return (end-pos . next-start-pos) ; takes prev-end-pos as an argument ; next-start-pos nil for last record post-last-string post-last-regexp post-last-regexp-submatch) (defun db-make-n-line-sep-function (n) "Return a function useful when all records have exactly N lines on disk. This is for use with the `:record-separator-function' control property." `(lambda (prev-end) (forward-line ,n) (cons (point) (unless (eobp) (point))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Manipulating database records ;;; (defun database-add-record (record db &optional location) ;; Add RECORD to DATABASE. If optional third argument LOCATION is a number, ;; insert immediately before that index; if it is a function, call it with ;; the current index to get the new index (modulo operation included); if it ;; is nil, insert at the end. (let* ((vov (edb--1D db :vov)) (vsz (length vov)) (new vov) (bno (edb--1D db :nrecords)) ; before (atz (cond ((numberp location) ; 0-based index to insert at (1- location)) ((functionp location) (% (1- (funcall location (edb--S :index))) bno)) ((not location) bno)))) ;; realloc if necessary (unless (< bno vsz) (setq new (make-vector (+ 10 bno) nil)) ; todo: parameterize (dotimes (i atz) (aset new i (aref vov i)))) ;; shift forward to leave a hole (do ((i bno (1- i))) ((= atz i)) (aset new i (aref vov (1- i)))) ;; add it (aset new atz record) (unless (eq new vov) (edb--1D! db :vov new)) (edb--1D! db :nrecords (1+ bno)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Mapping over a database ;;; (defvar db-inform-interval 100 "When doing a lengthy computation, inform the user of progress every this many records. If nil, don't inform.") ;; Mapping functions dynamically bind `db-lmap-index'. (defvar db-lmap-index nil "The current index in a call to `db-lmap'.") (defun db-lmap (lmapfunc db &optional hide message accumulate) ;; Use LMAPFUNC instead of simply FUNC to avoid a dynamic binding conflict. ;; In the body, variable `db-lmap-index' is the index of the record. ;; See `db-maprecords'. (let* ((vov (edb--1D db :vov)) (db-lmap-index 1) (htag (edb-tag :hiddenp db)) (results (when accumulate (list nil))) (--hit (assq 'db-inform-interval (database-locals db))) (--infint (if --hit (cdr --hit) db-inform-interval)) (tp results) lmaprecord v) (setq message (and --infint message)) (dotimes (i (edb--1D db :nrecords)) (setq db-lmap-index (1+ i) lmaprecord (aref vov i)) (unless (and hide (edb-tagp htag lmaprecord)) (setq v (funcall lmapfunc lmaprecord)) (when accumulate (setcdr tp (list v)) (setq tp (cdr tp)))) (when (and message (zerop (% db-lmap-index --infint))) (db-message message db-lmap-index))) (when accumulate (cdr results)))) (defun db-maprecords (func &optional db hide message accumulate) "Apply FUNC to every record in current database in order of ascending index. Optional second arg DB specifies a database to use other than the current one. Optional third arg HIDE non-nil means apply FUNC only to unhidden records. If optional fourth arg MESSAGE is non-nil, it should be a format string containing one numeric \(%d\) specifier. That message will be issued every `db-inform-interval' records. If optional fifth arg ACCUMULATE is non-nil, return a list of the results; otherwise return nil." (db-lmap (lambda (record) (funcall func record)) (or db dbc-database) hide message accumulate)) ;;;###badname (defalias 'maprecords 'db-maprecords) ;;; db-rep.el ends here edb-1.31/lisp/db-search.el0000444000175000017500000001013210745616666013521 0ustar ttnttn;;; db-search.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;;; Code: (defvar database-search-mode-map (copy-keymap database-edit-mode-map) "Keymap for database data display buffer in edit mode.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Searching primitives ;;; ;;;###autoload (defun db-parse-match-pattern (string ds) ;; These connectives and prefixes are listed in order of precedence. ;; [That order is rather unconventional. Also, no grouping. --ttn] ;; The latter prefixes used to be preceded by [ \t]* and followed by [ \t]+; ;; for instance, (defvar dbm-<-prefix "^[ =t]*<[ \t]+"). (let ((c-and "[ \t]+and[ \t]+") (c-or "[ \t]+or[ \t]+") (p-not "^[ \t]*not[ \t]+") (p-< "^<") (p-> "^>") (p-= "^=")) (flet ((try (x) (string-match x string)) (sub (x) (db-parse-match-pattern x ds)) (p1o (x) (db-callconvert (edb--1ds-display->actual ds) x nil nil nil)) (b () (substring string 0 (match-beginning 0))) (e () (substring string (match-end 0)))) (cond ((try c-and) `(db-match-and ,(sub (b)) (sub (e)))) ((try c-or) `(db-match-or ,(sub (b)) (sub (e)))) ;; no infix connectives in string ((try p-not) `(db-match-not ,(sub (e)))) ((try p-<) `(db-match-< ,(p1o (e)))) ((try p->) `(db-match-> ,(p1o (e)))) ((try p-=) `(db-match-= ,(p1o (e)))) (t (db-callconvert (or (edb--1ds-match-display->actual ds) (edb--1ds-display->actual ds)) string nil nil nil)))))) ;;;###autoload (defun db-print-match-pattern (pat ds) (flet ((sub (x) (db-print-match-pattern x ds)) (p1o (x) (db-callconvert (edb--1ds-actual->display ds) x nil nil))) (let* ((type (when (listp pat) (car pat))) (one (and type (cadr pat))) (two (and type (caddr pat)))) (case type ;; extra space around AND to emphasize its low precedence (db-match-and (concat (sub one) " AND " (sub two))) (db-match-or (concat (sub one) " OR " (sub two))) (db-match-not (concat "NOT " (sub one))) (db-match-< (concat "< " (p1o one))) (db-match-> (concat "> " (p1o one))) (db-match-= (concat "= " (p1o one))) ;; pat was not a list or the type wasn't recognized (t (db-callconvert (or (edb--1ds-match-actual->display ds) (edb--1ds-actual->display ds)) pat nil nil)))))) ;;;###autoload (defun db-match (pat targ rs) (flet ((m (x) (db-match x targ rs)) (rso (x) (funcall (db-rs-ordfunc rs) x targ)) (rsm (x) (funcall (edb--1rs-match-function rs) x targ))) (if (listp pat) (let ((one (cadr pat)) (two (caddr pat))) (case (car pat) (db-match-and (and (m one) (m two))) (db-match-or (or (m one) (m two))) (db-match-not (not (m one))) (db-match-< (= 1 (rso one))) (db-match-> (= -1 (rso one))) (db-match-= (= 0 (rso one))) (t (rsm pat)))) (rsm pat)))) (provide 'db-search) ;;; db-search.el ends here edb-1.31/lisp/db-sort.el0000444000175000017500000005005010745616666013246 0ustar ttnttn;;; db-sort.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Ordering-fields and field-priorities refer to the same thing. ;; Order funcs preferred over sort funcs. ;;; Code: (defvar db-converted-ofields) ; used dynamically ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Variables ;;; (defvar db-sort-modifies-p nil "*If non-nil, then sorting a database marks it as modified too.") ;; Field priorities is a cons of two lists; the first list is those that ;; will be used, and the the second set is the ignored fields. Ignorance ;; is only in the user interface; EDB always remembers everything. ;; Each list consists of (fieldnumber . order-info) pairs such that every ;; field is accounted for exactly once. The order-info is 'increasing, ;; 'decreasing, or a cons of (type . value) where type is 'order-function or ;; 'sort-function. ;; Priorities are initially associated w/ the database. On first use ;; it becomes format-local. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Sort ;;; ;; fixme: Implement "hidden at end" as synthetic field (attribute). --ttn ;;;###autoload (defun database-sort (db &optional sorter hidden-records-at-end-p) "Sort and return DB, which is also side-effected. If DB is nil, use the current database. SORTER is either a field priorities list or a function which takes two records as arguments and returns t if r1 < r2." (db-message "Sorting...") (unless db (setq db dbc-database)) (unless (= 0 (edb--1D db :nrecords)) (let (db-converted-ofields) (unless (functionp sorter) (setq db-converted-ofields (db-convert-ordering-fields sorter db) sorter 'db-record-lessp)) (edb--snap! db (edb--1D db :nrecords) (sort (db-lmap 'identity db nil nil t) (lambda (r1 r2) (funcall sorter r1 r2)))))) (let ((hit (assq 'db-sort-modifies-p (database-locals dbc-database)))) (when (if hit (cdr hit) db-sort-modifies-p) (database-set-modified-p db t) (force-mode-line-update))) (db-message "Sorting...done") db) (defun db-convert-ordering-fields (ofields db) (let ((all-rs (edb--1D db :elaborated-rfspecs)) (nm2no (edb--1D db :nm2no)) f fno sortinfo type value) (mapcar (lambda (spec) (setq f (car spec) fno (if (integerp f) f (gethash f nm2no)) sortinfo (cdr spec)) (cons fno (if (atom sortinfo) (db-rs-ordfunc (aref all-rs fno) (eq sortinfo 'decreasing)) (setq type (car sortinfo) value (cdr sortinfo)) (cond ((eq 'order-function type) value) ((eq 'sort-function type) ;; fixme: lame. --ttn (error "Trying to order field `%s', %s" (if (symbolp f) f (db-fname<-fno f db)) "but only sort function provided.")) (t (error "Unrecognized type in %s" sortinfo)))))) (car (or ofields (database-field-priorities db)))))) (defun db-make-ordering-fields-canonical (db) ;; Make sure that every car is a number (not a fieldname) and ;; that every field is represented. (let* ((ofields (database-field-priorities db)) (nfields (length (database-fieldnames db))) (seen (make-vector nfields nil)) (nm2no (edb--1D db :nm2no)) fno sortinfo value (check-field (lambda (spec) (setq fno (if (numberp (car spec)) (car spec) (gethash (car spec) nm2no)) sortinfo (cdr spec)) (cond ((not fno) (db-warning "`%s' not a valid field; ignoring it." (car spec)) nil) ((aref seen fno) (db-warning "`%s' seen already; ignoring subsequent." (db-fname<-fno fno db)) nil) (t (aset seen fno t) (cons fno (cond ((eq sortinfo 'decreasing) 'decreasing) ((atom sortinfo) (when (and sortinfo (not (eq sortinfo 'increasing))) (db-warning "%s %s being changed to `%s'." "Unrecognized ordering symbol" sortinfo "increasing")) 'increasing) ;; sortinfo is a list ((or (eq (car sortinfo) 'order-function) (eq (car sortinfo) 'sort-function)) (unless (functionp (cdr sortinfo)) (db-warning "%s %s %s %s %s." (cdr sortinfo) "is claimed to be a" (car sortinfo) "but doesn't look like" "a function to me")) sortinfo) (t (error "Unrecognized type in %s" sortinfo)))))))) (sig-fields (delq nil (mapcar check-field (car ofields)))) (nonsig-fields (delq nil (mapcar check-field (cdr ofields)))) missing-fields) (dotimes (fno nfields) (unless (aref seen fno) (db-warning "%s doesn't appear; adding it." (db-fname<-fno fno db)) (push (cons fno 'increasing) missing-fields))) (cons sig-fields (if missing-fields (append nonsig-fields missing-fields) nonsig-fields)))) ;; Uses the `db-converted-ofields' dynamic variable. (defun db-order-records (r1 r2) ;; Return -1, 0, or 1 depending on whether records R1 and R2 are <, =, or >. (let ((ofields db-converted-ofields) (result 0) fno ofunc) (while (and ofields (zerop result)) (setq fno (car (car ofields)) ofunc (cdr (car ofields)) ofields (cdr ofields) result (funcall ofunc (aref r1 fno) (aref r2 fno)))) result)) (defun db-record-lessp (r1 r2) ;; Return t if record R1 < R2. Use `db-order-records'. (= -1 (db-order-records r1 r2))) (defun database-sorted-p (db &optional sorter) ;; Return t if DB is sorted, nil otherwise. ;; Optional argument SORTER is used as the function. (db-with-sorter db (catch t (let ((vov (edb--1D db :vov)) (frp t)) ; first record ;; Don't do anything for the first record. ;; If some other record is less than its predecessor, complain. (db-lmap (lambda (record) (if frp (setq frp nil) (when (funcall sorter record (aref vov (1- (1- db-lmap-index)))) (throw t nil)))) db) t)))) (defun database-ordered-p (db &optional orderer) ;; Return t if DB is ordered, nil otherwise. ;; Optional argument ORDERER is used as the ordering function. (db-with-orderer db (catch t (let ((vov (edb--1D db :vov)) (frp t)) ; first record (db-lmap (lambda (record) (if frp (setq frp nil) (when (= 1 (funcall orderer (aref vov (1- (1- db-lmap-index))) record)) (throw t nil)))) db) t)))) (defmacro db-with-orderer (database &rest body) (declare (indent 1) (debug (sexp body))) `(let (db-converted-ofields) (unless orderer ; dynamically bound (setq orderer 'db-order-records db-converted-ofields ;; mernst sez: stupid way to call this function. ;; ttn sez: why? (db-convert-ordering-fields nil ,database))) ,@body)) (defmacro db-with-sorter (database &rest body) (declare (indent 1) (debug (sexp body))) `(let (db-converted-ofields) (if (not sorter) ; dynamically bound (setq sorter 'db-record-lessp db-converted-ofields ;; mernst sez: stupid way to call this function. ;; ttn sez: why? (db-convert-ordering-fields nil ,database))) ,@body)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Sorting interface ;;; ;; Commands: ;; cursor movement ;; kill a line ;; yank a line ;; sort on this field only ;; accept this ordering, sort with it, and make it the default ;; accept this ordering and sort with it, but don't make it the default ;; toggle ordering direction (increasing vs decreasing) or -to-end-p ;; input custom ordering info: a list or a function name ;;;###autoload (defun database-sort-interface (db) ;; Assume current-buffer is data display buffer. (let ((canon (db-make-ordering-fields-canonical db)) (ddb (current-buffer))) (switch-to-buffer (get-buffer-create (concat "Ordering info for " (database-print-name db)))) (database-sort-interface-mode) (set (make-local-variable 'edb--bprops) (edb--rinit '(:edb1 :bprops) (current-buffer) :size 5 :test 'eq :weakness 'key)) (set (make-local-variable 'dbc-database) db) (edb--S! :ddb ddb) (edb--S! :hendp (edb--1D db :hendp)) ;; Fill the buffer with info. (let (buffer-read-only) (erase-buffer) (insert "==== Significant fields:\n") (save-excursion (dolist (item (car canon)) (dbsi-format item :sig)) (insert (propertize "==== Nonsignificant fields:\n" :which :sig)) (dolist (item (cdr canon)) (dbsi-format item :non)) (insert "==== Hidden records to end: " (if (edb--S :hendp) "Yes" "No ")))) (message "%s, %s, %s, %s, %s" "u = use" "RET = also make default" "! = this field only" "q = abort" "? = help"))) (defun database-sort-interface-mode () "Sort interface buffer for choosing fields upon which to sort a database. You can: reorder fields with `dbsi-kill-line' and `dbsi-yank-line'; specify how a particular field should be ordered with `dbsi-increasing' `dbsi-decreasing', `dbsi-ordering-function' and `dbsi-sorting-function'; change whether hidden records go at the end of the sorted order with `dbsi-toggle-hidden-to-end'; exit the sort interface with one of the following: `dbsi-use-ordering-make-database-default', `dbsi-use-ordering-make-buffer-default', `dbsi-quit-clear-buffer-default' `dbsi-use-ordering', `dbsi-this-field-only', `dbsi-quit'. More specifically: \\{database-sort-mode-map}" (setq major-mode 'database-sort-interface-mode) (setq mode-name "Database Sort Interface") (set-buffer-modified-p nil) (setq buffer-read-only t truncate-lines t) (use-local-map database-sort-mode-map) (setq mode-line-format '("--- %17b [" (-3 . "%p") "]-%-"))) (defvar database-sort-mode-map nil "Keymap for database data display buffer in view mode.") (unless database-sort-mode-map (let ((m (make-sparse-keymap))) (suppress-keymap m) (mapc (lambda (key-def) (define-key m (car key-def) (cdr key-def))) '(("\C-k" . dbsi-kill-line) ("\C-y" . dbsi-yank-line) ("!" . dbsi-this-field-only) ("\r" . dbsi-use-ordering-make-database-default) ("\C-c\C-c" . dbsi-use-ordering-make-database-default) ("A" . dbsi-use-ordering-make-buffer-default) ("U" . dbsi-use-ordering-make-buffer-default) ("c" . dbsi-quit-clear-buffer-default) ("a" . dbsi-use-ordering) ("u" . dbsi-use-ordering) ("t" . dbsi-toggle-hidden-to-end) ("o" . dbsi-ordering-function) ("s" . dbsi-sorting-function) ("i" . dbsi-increasing) ("d" . dbsi-decreasing) ("q" . dbsi-quit) ("\M-n" . [?\C-k ?\C-n ?\C-y ?\C-p]) ("\M-p" . [?\C-k ?\C-p ?\C-u ?\C-y]) ("?" . describe-mode))) (setq database-sort-mode-map m))) ;; Insert item and trailing newline. (defun dbsi-format (item which) (flet ((pinsert (s) (insert (propertize s :item item :which which)))) (pinsert (format " %-16s " (db-fname<-fno (car item) dbc-database))) (if (atom (cdr item)) (pinsert (format "%s" (cdr item))) (pinsert (format "%s [%s]" (cdr (cdr item)) (car (cdr item))))) (pinsert "\n"))) (defun dbsi-reformat (item) (beginning-of-line) (let ((which (get-text-property (point) :which)) buffer-read-only) (kill-line 1) (save-excursion (dbsi-format item which)))) ;;; Moving fields around. (defun dbsi-kill-line () "Move field on current line to the top of the nonsignificant list." (interactive) (let (line beg buffer-read-only) (unless (get-text-property (point) :item) (error "No field on this line.")) (beginning-of-line) (setq beg (point)) (save-excursion (forward-line 1) (setq line (buffer-substring beg (point))) (delete-region beg (point)) (goto-char (point-min)) (search-forward "Nonsignificant fields:\n") (setq beg (point)) (insert line) (put-text-property beg (point) :which :non)))) (defun dbsi-yank-line (afterp) "Yank the field from the top of the nonsignificant list. Insert it before the current line. Prefix arg means point doesn't move." (interactive "P") (let (eob which line b e buffer-read-only) (unless (eq :sig (get-text-property (point) :which)) (error "Can't insert here.")) (save-excursion (setq b (progn (goto-char (point-min)) (search-forward "Nonsignificant fields:\n") (point)) e (progn (forward-line 1) (point))) (unless (get-text-property b :item) (error "Nothing to yank.")) (setq line (propertize (buffer-substring b e) :which :sig)) (delete-region b e)) (unless (get-text-property (point) :item) (setq afterp nil)) (beginning-of-line) (if afterp (save-excursion (insert line)) (insert line)))) ;;; Changing info about hiding. (defun dbsi-toggle-hidden-to-end () "Toggle whether hidden records should all be placed at the end of the sorted order or should be sorted according to the same criteria as non-hidden records." (interactive) (save-excursion (let (buffer-read-only) (edb--S! :hendp (not (edb--S :hendp))) (goto-char (point-max)) (backward-delete-char 3) (insert (if (edb--S :hendp) "Yes" "No "))))) ;;; Changing (defun dbsi-increasing () "Specify that the field at point should use an increasing ordering." (interactive) (let ((item (get-text-property (point) :item))) (when item (setcdr item 'increasing) (dbsi-reformat item)))) (defun dbsi-decreasing () "Specify that the field at point should use a decreasing ordering." (interactive) (let ((item (get-text-property (point) :item))) (when item (setcdr item 'decreasing) (dbsi-reformat item)))) (defun dbsi-ordering-function () "Specify an ordering function for the field at point. An ``ordering function'' returns -1, 0, or 1 depending on whether its first argument is less than, equivalent to, or greater than its second argument." (interactive) (let ((item (get-text-property (point) :item))) (when item (setcdr item (cons 'order-function (read-from-minibuffer "Ordering function: " nil nil t))) (dbsi-reformat item)))) (defun dbsi-sorting-function () "Specify a sorting function for the field at point. A ``sorting function'' returns t if its first argument is less than its second argument and nil otherwise." (interactive) (let ((item (get-text-property (point) :item))) (when item (setcdr item (cons 'sort-function (read-from-minibuffer "Sorting function: " nil nil t))) (dbsi-reformat item)))) ;;; Quitting (defun dbsi-quit () "Abort the sort and exit the sort interface." (interactive) (let ((ddb (edb--S :ddb))) (kill-buffer nil) (switch-to-buffer ddb) (db-message "Aborting sort"))) (defun dbsi-quit-clear-buffer-default () "Clear the default sort order for this buffer and exit the sort interface without sorting. In the future, the default sort order will come from the database." (interactive) (let ((ddb (edb--S :ddb))) (kill-buffer nil) (switch-to-buffer ddb) (edb--S! :field-priorities nil) (db-message "Reset buffer-local default sort order; didn't sort"))) ;;; Specifying an ordering. (defun dbsi-this-field-only () "Sort according to only the field at point. All editing of other fields is ignored." (interactive) (let ((item (get-text-property (point) :item))) (unless item (error "No field on this line.")) (dbsi-use-ordering (cons (list item) nil)))) (defun dbsi-ordering<-buffer () (let (sig non p item which) (setq p (point-min)) (while (setq p (next-single-property-change p :item)) (when (setq item (get-text-property p :item)) (if (eq :sig (get-text-property p :which)) (push item sig) (push item non)))) (cons (nreverse sig) (nreverse non)))) (defun dbsi-use-ordering-make-database-default () "Use the current ordering to sort, and make it the default for future sorts of this database." (interactive) (with-current-buffer (edb--S :ddb) (edb--S! :field-priorities nil)) (edb--1D! dbc-database :hendp (edb--S :hendp)) (setf (database-field-priorities dbc-database) (dbsi-ordering<-buffer)) (dbsi-use-ordering (database-field-priorities dbc-database))) (defun dbsi-use-ordering-make-buffer-default () "Use the current ordering to sort, and make it the default for future sorts in this data display buffer only." (interactive) (let ((ordering (dbsi-ordering<-buffer)) (hendp (edb--S :hendp))) (with-current-buffer (edb--S :ddb) (edb--S! :field-priorities ordering) (edb--S! :hendp hendp)) (dbsi-use-ordering ordering))) (defun dbsi-use-ordering (&optional ordering) "Use the current ordering for this sort only." (interactive) (database-sort dbc-database (or ordering (dbsi-ordering<-buffer)) (edb--S :hendp)) (let ((ddb (edb--S :ddb))) (kill-buffer nil) (switch-to-buffer ddb) (dbf-finished-sorting))) (provide 'db-sort) ;;; db-sort.el ends here edb-1.31/lisp/db-summary.el0000444000175000017500000005434311016233743013744 0ustar ttnttn;;; db-summary.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Patterned in part after rmail-new-summary. ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Variables ;;; ;;; ;;; Hooks ;;; (defvar database-summary-mode-hooks nil "Normal hook run when switching to Database Summary mode.") ;;; ;;; Summary variables ;;; (defun dbs-set-index (index) (edb--S! :index index) (edb--S! :index-fraction (format "%d/%d" index (edb--S :nrecords)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Macros for working in the correct buffer ;;; (defmacro db-in-data-display-buffer (&rest body) (declare (indent 0) (debug body)) `(db-in-buffer (or (edb--S :data-display-buffer) (current-buffer)) ,@body)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Creating the summary ;;; (defun db-summary () "Display a summary (or directory) of records in a separate buffer. When called from the summary buffer, this updates the summary. The displayed format can be set with `dbf-set-summary-format'." (interactive) (db-in-data-display-buffer (cond ((= 0 (edb--1D dbc-database :nrecords)) (delete-windows-on (edb--S :sumbuf)) (db-message "Database is empty")) (t (let ((ddb (current-buffer)) (sumbuf (edb--S :sumbuf))) (unless (edb--S :sumfun) (dbf-set-summary-format (edb--S :sumfmt))) (unless sumbuf (edb--S! :sumbuf (with-current-buffer (generate-new-buffer (format "%s-summary" (buffer-name ddb))) (set (make-local-variable 'edb--bprops) (edb--rinit '(:edb1 :bprops) (current-buffer) :size 5 :weakness 'key)) (set (make-local-variable 'dbc-database) (buffer-local-value 'dbc-database ddb)) (edb--S! :data-display-buffer ddb) (database-summary-mode) (edb--S! :summaries (make-hash-table :weakness 'key)) (setq sumbuf (current-buffer))))) (when (with-current-buffer sumbuf (dbs-out-of-date-p)) (dbf-fill-summary-buffer)) (pop-to-buffer sumbuf) (edb--S! :data-display-buffer ddb) ;; Go to proper line. (dbs-move-to-proper-record)))))) ;; This is spelled out instead of being db-summary-mode because it's a ;; "standalone" major mode, while db-edit-mode and db-view-mode are ;; "cooperating" major modes (unimportant distinction, really --ttn). (defun database-summary-mode () "Summary buffer for database mode. Most keystrokes perform the same function they do in the data display buffer. Key bindings: \\{database-summary-mode-map}" (setq major-mode 'database-summary-mode) (setq mode-name "Database Summary") (set-buffer-modified-p nil) (setq buffer-read-only t) (use-local-map database-summary-mode-map) (setq mode-line-format (list "----- " (format "%-17s" (buffer-name (edb--S :data-display-buffer))) " %[(" 'mode-name 'minor-mode-alist '(:eval (concat (and (edb--S :hide-p) " Hide") " " (edb--S :index-fraction))) ")%]---" '(-3 . "%p") "-%-")) (edb--1run-hooks 'database-summary-mode-hooks) ;; Force an update. (edb--S! :nrecords -1)) (defsubst db-summary-buffer-p () "T if this buffer is a database summary buffer." (eq major-mode 'database-summary-mode)) (defun db-summary-subset () "Make EDB summary-listing based on hits of STRING search, of FIELD." (interactive) (db-mark-searched-records) (db-hide-unmarked-records) (db-toggle-show-hidden-records 0) (db-summary) (db-hiding-toggle 0) (db-hiding-toggle 1)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Filling the summary ;;; (defun dbs-insert-record-summary (record mhp mtag htag) ;; mhp -- mark-hidden-records-p (let ((one (if (edb-tagp mtag record) "+" " ")) (two (if (and mhp (edb-tagp htag record)) "[" " ")) (rest (substring (gethash record (edb--S :summaries)) 2))) (insert one two rest))) (defun dbf-fill-summary-buffer (&optional movep) ;; fixme: check database nonempty. --ttn (let ((sum (edb--S :sumfun)) (lines (edb--1D dbc-database :sum1lines)) (hide (and (edb--S :invisible-hidden-p) (edb--S :hide-p))) (mhp (edb--S :hide-p)) (sumbuf (edb--S :sumbuf))) (when sumbuf (with-current-buffer sumbuf (let ((ht (edb--S :summaries)) (mtag (edb-tag :markedp dbc-database)) (htag (edb-tag :hiddenp dbc-database)) buffer-read-only) (erase-buffer) (db-message "Computing summary...") (db-lmap (lambda (record) (unless (gethash record ht) (puthash record (funcall sum record) ht)) (dbs-insert-record-summary record mhp mtag htag)) dbc-database hide "Computing summary...%d") (db-message "Computing summary...done") ;; get rid of last newline. (backward-delete-char 1) (set-buffer-modified-p nil) (edb--S! :nrecords (edb--1D dbc-database :nrecords)) (edb--S! :recompute-p nil) (edb--S! :index 0)) (when movep (dbs-move-to-proper-record)))))) (defun dbf-update-summary-marks () ;; Update just the marked and hidden summary markings efficiently. (when (edb--S :sumbuf) (with-current-buffer (edb--S :sumbuf) (let ((opoint (point)) (hidep (not (or (not (edb--S :invisible-hidden-p)) (not (edb--S :hide-p))))) (mtag (edb-tag :markedp dbc-database)) (htag (edb-tag :hiddenp dbc-database)) line hiddenp) (unwind-protect (let ((sum1lines (edb--1D dbc-database :sum1lines)) buffer-read-only) (goto-char (point-min)) (db-lmap (lambda (record) (delete-char 1) (insert (if (edb-tagp mtag record) "+" " ")) (backward-char 1) (setq line 0 hiddenp (and (edb--S :hide-p) (edb-tagp htag record))) ;; Each summary item spans exactly sum1lines screen lines. (while (< line sum1lines) (forward-char 1) (delete-char 1) (insert (if hiddenp "[" " ")) (forward-line 1) (incf line))) dbc-database hidep)) (goto-char opoint)))))) (defun dbf-update-summary-item (index) ;; Update just changes to one record in the summary efficiently. (let ((record (aref (edb--1D dbc-database :vov) (1- index))) (mtag (edb-tag :markedp dbc-database)) (htag (edb-tag :hiddenp dbc-database)) (sum (edb--S :sumfun)) (sumbuf (edb--S :sumbuf))) (when (and sumbuf (or (not (edb-tagp htag record)) (not (edb--S :invisible-hidden-p)) (not (edb--S :hide-p)))) (db-in-buffer sumbuf (let ((orig (edb--S :index))) (unwind-protect (let ((ht (edb--S :summaries)) buffer-read-only) (puthash record (funcall sum record) ht) (dbs-move-to-proper-record index) ;; assuming at beginning of line (delete-region (point) (progn (forward-line (edb--1D dbc-database :sum1lines)) (point))) (dbs-insert-record-summary record (edb--S :hide-p) mtag htag)) ;; save old line and column instead. (dbs-move-to-proper-record orig))))))) (defun db-format->lines/sforms (format db indent nlp vheightp) ;; Take a format and return a cons of two values: a number and a list. ;; The list is list of forms which, when evaluated with variable ;; `formatted-record' bound, evaluate to strings; these can be used as ;; argumentes to concat, insert, etc. The number is the number of lines ;; occupied by the items when inserted. ;; ;; Signal an error if any displayspec has nonequal min-height and ;; max-height, unless VHEIGHTP is non-nil, in which case the number ;; returned is a minimum. NLP non-nil means add a newline. (let ((ph (and (string-match "\\\\\\\\" format) ; backslash place holder (db-unused-char-in-string format))) (lines 0) results beg end ds minh maxh) (when (and indent (> indent 0)) (setq format (concat (make-string indent 32) (replace-regexp-in-string "\n" (concat "\n" (make-string indent 32)) format)))) (when ph (setq format (replace-regexp-in-string (regexp-quote "\\\\") (char-to-string ph) format))) (while (string-match db-ds+opts-rx format) (setq beg (match-beginning 0) end (match-end 0) ds (db-dspec<-string format db) minh (edb--1ds-min-height ds) maxh (edb--1ds-max-height ds)) ;; fixme: should not be necessary. --ttn (unless minh (setf minh (setf (edb--1ds-min-height ds) 1))) (unless (or vheightp maxh) (setf maxh (setf (edb--1ds-max-height ds) minh))) (if (or vheightp (= minh maxh)) (incf lines (1- minh)) (error "Min- (%s) and max (%s) heights differ in summary displayspec." minh maxh)) (unless (zerop beg) (let ((literal (substring format 0 beg))) (when ph (subst-char-in-string ph ?\\ literal t)) (push literal results) (incf lines (db-count-newlines literal)))) (push `(db-ds-printed ,ds formatted-record) results) (setq format (substring format end))) (when nlp (setq format (concat format "\n"))) (unless (equal "" format) (when ph (subst-char-in-string ph ?\\ format t)) (push format results)) (incf lines (db-count-newlines format)) (cons lines (nreverse results)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Synching the format and summary buffers ;;; (defsubst dbs-in-synch-p () (= (with-current-buffer (edb--S :data-display-buffer) (edb--S :index)) (edb--S :index))) (defsubst dbs-out-of-date-p () (or (edb--S :recompute-p) (not (= (edb--1D dbc-database :nrecords) (edb--S :nrecords))))) (defsubst dbf-set-summary-out-of-date-p () (when (edb--S :sumbuf) (with-current-buffer (edb--S :sumbuf) (edb--S! :recompute-p t)))) (defun dbs-synch-format-with-summary () ;; Ensure that the data display and summary buffers ;; have the same current record. (cond ((dbs-out-of-date-p) (dbs-synch-summary-with-format)) ((dbs-in-synch-p)) (t (let ((sum-index (edb--S :index))) (db-in-buffer (edb--S :data-display-buffer) (db-select-record sum-index)))))) (defun dbs-synch-summary-with-format () (when (dbs-out-of-date-p) (db-in-buffer (edb--S :data-display-buffer) (dbf-fill-summary-buffer))) ;; If we just did the above, it will clearly be out of synch. ;; But it might be even if it wasn't out of date. (unless (dbs-in-synch-p) (dbs-move-to-proper-record))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Moving about ;;; (defsubst dbs-goto-nth-summary (n) ;; NOTE: If hidden records aren't shown in the summary (and that should be ;; an option), then this is wrong. And in that case it's better to do ;; relative than absolute motion. (goto-line (1+ (* (edb--1D dbc-database :sum1lines) (1- n)))) (edb--S! :point (point))) (defun dbs-move-to-proper-record (&optional index) "Move point to the summary of the record shown in the format or to INDEX." ;; Make no assumptions about the current index. (if (with-current-buffer (edb--S :data-display-buffer) (or (not (edb--S :hide-p)) (not (edb--S :invisible-hidden-p)))) (let ((index (or index (with-current-buffer (edb--S :data-display-buffer) (edb--S :index))))) (dbs-goto-nth-summary index) (dbs-set-index index)) (let ((prev 0) (last nil) (pidx (or index ; proper index (with-current-buffer (edb--S :data-display-buffer) (edb--S :index))))) (db-lmap (lambda (ignored-record) (if (<= db-lmap-index pidx) (setq prev (1+ prev) last db-lmap-index) ;; Past it but still haven't found a nonhidden record. (unless last (setq prev 1 last db-lmap-index)))) dbc-database t) ;; If there are no displayed records at all, this will fail. (unless (= last pidx) (db-message "Record %s does not appear in the summary buffer" pidx)) (dbs-goto-nth-summary prev) (dbs-set-index last)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Movement commands ;;; (defsubst dbs-forward-record (arg) ;; Move point forward ARG records in the summary buffer, ;; remembering the start position of that record. (goto-char (edb--S :point)) (db-forward-line-wrapping (* (edb--1D dbc-database :sum1lines) arg)) (edb--S! :point (point))) (defun dbs-next-record-ignore-hiding (arg) "Go to the ARGth next record, ignoring hiding. That is, all records, even those which are hidden, are counted." (interactive "p") (if (not (with-current-buffer (edb--S :data-display-buffer) (not (edb--S :invisible-hidden-p)))) (db-next-record-ignore-hiding arg) (dbs-synch-format-with-summary) (db-in-buffer (edb--S :data-display-buffer) (db-next-record-ignore-hiding arg)) (dbs-forward-record arg) (dbs-set-index (with-current-buffer (edb--S :data-display-buffer) (edb--S :index))))) (defun dbs-previous-record-ignore-hiding (arg) "Go to the ARGth previous record, ignoring hiding. That is, all records, even those which are hidden, are counted." (interactive "p") (dbs-next-record-ignore-hiding (- arg))) (defun dbs-scroll-up () (interactive) (scroll-up) (db-jump-to-point)) (defun dbs-scroll-down () (interactive) (scroll-down) (db-jump-to-point)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Summary Mode commands ;;; (defvar database-summary-mode-map nil "Keymap for database summary buffer.") (unless database-summary-mode-map (let ((m (make-sparse-keymap)) (meta (list meta-prefix-char))) (suppress-keymap m) (mapc (lambda (key-def) (define-key m (let ((key (car key-def))) (if (consp key) (concat meta (car key)) key)) (cdr key-def))) '(("t" . toggle-truncate-lines) ;; Moving around in the database ("n" . db-next-record) ("p" . db-previous-record) ("\C-n" . db-next-record) ("\C-p" . db-previous-record) ("<" . db-first-record) (">" . db-last-record) (("<") . db-first-record) ((">") . db-last-record) ("j" . db-jump-to-record) (" " . db-next-screen-or-record) ("\177" . db-previous-screen-or-record) (("n") . dbs-next-record-ignore-hiding) (("p") . dbs-previous-record-ignore-hiding) (("\C-n") . db-next-marked-record) (("\C-p") . db-previous-marked-record) ;; Exiting summary mode ("e" . dbs-edit) ("v" . dbs-view) ("q" . dbs-quit) ("x" . dbs-exit) ;; Adding and removing records ("a" . db-add-record) ("i" . db-add-record) ("d" . dbs-delete-record) ("k" . dbs-delete-record) ("o" . db-output-record-to-db) ("c" . db-copy-record) ;; Sorting ("S" . db-sort) ;; Searching commands ("s" . db-search) ;;("S" . db-incremental-search) ("\C-s" . db-isearch-forward) ("\C-r" . db-isearch-backward) ;; Everything else ("?" . describe-mode) ("O" . db-hide-record) (("o") . db-hiding-toggle) (("O") . db-hiding-set) (("\C-o") . db-toggle-show-hidden-records) ("g" . db-summary) ("h" . db-summary) ("D" . db-summary) ("m" . db-mark-record) ("r" . db-report) ("\C-xr" . db-revert-database) ("\C-v" . dbs-scroll-up) (("v") . dbs-scroll-down) ("\C-x\C-q" . db-toggle-modifiable-p) ("\C-c\C-c" . dbs-exit) ("b" . undefined) ("f" . undefined) ("l" . undefined) ;;("u" . db-revert-record) ("w" . undefined) ("y" . undefined) ("z" . undefined))) (setq database-summary-mode-map m))) (defun dbs-view () "Manipulate this record in the data display buffer in View mode." (interactive) (pop-to-buffer (edb--S :data-display-buffer)) (db-view-mode)) (defun dbs-edit () "Manipulate this record in the data display buffer in Edit mode." (interactive) (pop-to-buffer (edb--S :data-display-buffer)) (when (eq 'database-view-mode major-mode) (db-first-field))) (defun dbs-quit () "Quit the summary buffer, and return to its data display buffer. Delete any windows showing the summary buffer prior to burying it." (interactive) (let ((ddb (edb--S :data-display-buffer)) (sum (current-buffer))) (delete-windows-on sum) (bury-buffer sum) (pop-to-buffer ddb))) (defun dbs-exit () "Exit the summary buffer, and return to its data display buffer. Delete any windows showing the summary buffer prior to killing it." (interactive) (let ((ddb (edb--S :data-display-buffer)) (sum (current-buffer))) (delete-windows-on sum) (kill-buffer sum) (pop-to-buffer ddb))) (defun dbs-delete-record (&optional force) "Delete the current record from the database. With a prefix argument, doesn't verify." (interactive "P") (when (or force (y-or-n-p "Delete this record? ")) (db-in-buffer (edb--S :data-display-buffer) (db-delete-record t)) ;; hope we're at the beginning of the record (let ((buffer-read-only nil)) (kill-line (edb--1D dbc-database :sum1lines)) (when (eobp) (goto-char (point-min)))) (edb--S! :nrecords (1- (edb--S :nrecords))) (db-message "Record deleted") (dbs-set-index (with-current-buffer (edb--S :data-display-buffer) (edb--S :index))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Menus ;;; (defvar database-summary-mode-menu '("Database" "SUMMARY Mode:" ["Update summary" db-summary t] ["Report" db-report t] "----" ("Motion" ["jump to record" db-jump-to-record t] ["last record" db-last-record t] ["first record" db-first-record t] "---" ["next" db-next-record t] ["next (screen)" db-next-screen-or-record t] ["next (marked)" db-next-marked-record t] ["next (ingore hiding)" db-next-record-ignore-hiding t] "---" ["prev" db-previous-record t] ["prev (screen) " db-previous-screen-or-record t] ["prev (marked)" db-previous-marked-record t] ["prev (ingore hiding)" db-previous-record-ignore-hiding t] "---" ["Isearch Backward" db-isearch-backward t] ["Isearch Forward" db-isearch-forward t] ) "----" ["View record" dbs-view t] ["Edit record" dbs-edit t] ["Delete Record" dbs-delete-record t] ["Add Record" db-add-record t] ["Mark Record" db-mark-record t] ["Hide Record" db-hide-record t] "----" ("Hiding" ["Hiding on/off" db-hiding-toggle t] ["Hiding hide/show (in summary)" db-toggle-show-hidden-records t] ["Un-hide all" db-unhide-all t] ["Un-mark all" db-unmark-all t] ["Mark un-hidden" db-mark-unhidden-records t] ["Hide un-marked" db-hide-unmarked-records t] ) "----" ["Sort database" db-sort t] ["Revert database" db-revert-database t] ["Save database" db-save-database t] ["Write database" db-write-database-file t] "----" ["Quit" dbs-quit t] ["Exit" dbs-exit t] ) "Menu for Database Summary mode.") ;; 'ignored for SYMBOL argument was giving me trouble. ;; Does this work in Lucid Emacs? (easy-menu-define ignored database-summary-mode-map "ignored-doc-string" database-summary-mode-menu) ;;; db-summary.el ends here edb-1.31/lisp/db-tagged.el0000444000175000017500000003001510745616666013511 0ustar ttnttn;;; db-tagged.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Provide support for files of tagged fields, such as ;; Name: John Doe ;; Age: 42 ;; Salary:22000 ;; This file adds to EDB basic support for parsing and generating ;; files where records consist of a group of lines with tags and ;; values. All functions and variables defined here start with the ;; prefix "db-tagged-". ;; The basic way to use this is to call `db-tagged-setup' with a list ;; describing the fields. There are hooks to parse out and generate ;; possible added entries that don't fit the basic model. There are ;; variables to customize all the separator strings and regexps for ;; complete parsing. These should be set by specifying overriding ;; attributes in the call to `db-tagged-setup'. ;; The field info passed to `db-tagged-setup' is a list with one entry ;; per field. Each entry is a three-element list: the field name, the ;; tag used to identify it in the file, and a short description for ;; documentation (not presently used). The field name can be a two ;; element list with a field name and type to use types other than the ;; default. Two values in the tag position are special, nil means that ;; it will be a computed field and is never stored in the database (and ;; thus doesn't need a tag), and the empty string marks a field where ;; "comments" are collected, comments consist of lines starting with the ;; separator, i.e. empty tags. ;; The default is records separated by blank lines, tags separated from ;; fields by ":", white space around the separator is not significant on ;; input, and that the separator should be followed by one tab on ;; output, and continuation lines start with whitespace. All of these ;; can be customized. ;;; Code: (require 'database) (eval-when-compile (require 'cl)) (eval-when-compile (defvar database)) ; used dynamically ;;;###autoload (defun db-tagged-setup (fspecs &rest attrs) "Ready the database to read files in tagged format. Argument FSPECS is a list of tagged-field specifications, one for each field in a database record. Each tagged-field specification is a three-element list of the field name \(a symbol\), the tag used to identify it in the file \(a string\), and a brief help string. Instead of a symbol, the tagged-field name may be a cons of the field name and its type. To indicate that a field is never found in the input file \(typically because it is computed on the fly\), use nil for its tag. ATTRS is a sequence of alternating keywords and values specifying overriding attributes. Here are the valid attributes and their default values: :tag-chars \"-_A-Za-z\" :pre-tag \"\" :pre-tag-regexp nil :pre-tag-output nil :separator \":\" :separator-regexp nil :separator-output nil :continuation \"\t\" :continuation-regexp \"[ \t]+\" :continuation-output nil :pre-parse-thunk nil :pre-write-function nil :post-write-function nil :index-function nil :default-field nil Note: Do not call `database-set-fieldnames-to-list' if using this function." (let ((details (edb--1D database :tagged-details)) (defaults (list :tag-chars "-_A-Za-z" :pre-tag "" :pre-tag-regexp nil :pre-tag-output nil :separator ":" :separator-regexp nil :separator-output nil :continuation "\t" :continuation-regexp "[ \t]+" :continuation-output nil :pre-parse-thunk nil :pre-write-function nil :post-write-function nil :index-function nil :default-field nil))) ;; Check attributes. (let ((ls attrs)) (while ls (unless (memq (car ls) defaults) (error "No such db-tagged attribute: %S" (car ls))) (setq ls (cddr ls)))) ;; First, try to detect whether this database was once in tagged file ;; layout, but is now in internal file layout. (if details (unless (gethash :converted-p details) (puthash :converted-p t details)) (apply 'edb--mputhash (setq details (edb--1D! database :tagged-details (make-hash-table :test 'eq :size 19))) :tagged-field-spec fspecs defaults) (database-set-fieldnames-to-list database (mapcar 'car fspecs) ;; Most fields are strings (or missing, here represented as nil) 'nil-or-string) ;; Save help strings. (let* ((ls (mapcar 'caddr fspecs)) (walk ls) (fno 0)) (while walk (setcdr walk (cons (car walk) (cdr walk))) (setcar walk fno) (incf fno) (setq walk (cddr walk))) (apply 'db-set-field-help database ls)) ;; Elaborate recordfieldspecs. FIXME: This should not be necessary. (let* ((all-rs (database-recordfieldspecs database)) (count (length all-rs))) (do ((fno 0 (1+ fno))) ((= fno count)) (aset all-rs fno (db-rfspec<-rftype (aref all-rs fno))))) (setf (database-read-record-from-region database) (lambda () (apply 'db-tagged-read (edb--1D database :tagged-read-kargs))) (database-write-region-from-record database) (lambda (record) (apply 'db-tagged-write record (edb--1D database :tagged-write-kargs))) (sepinfo-sep-string (database-record-sepinfo database)) "\n\n" (sepinfo-post-last-string (database-record-sepinfo database)) "\n") (add-hook 'db-after-read-hooks 'db-tagged-convert/index) ;; Override the defaults. (apply 'edb--mputhash details attrs) (macrolet ((D (k) `(gethash ,k details)) (D-! (k v) `(unless (D ,k) (setf (D ,k) ,v)))) ;; Compute downstream defaults. (D-! :pre-tag-regexp (regexp-quote (D :pre-tag))) (D-! :pre-tag-output (D :pre-tag)) (D-! :separator-regexp (concat "[ \t]*" (regexp-quote (D :separator)) "[ \t]*")) (D-! :separator-output (concat (D :separator) "\t")) (D-! :continuation-regexp (regexp-quote (D :continuation))) (D-! :continuation-output (D :continuation)) ;; Performance-motivated pre-computations. (flet ((P! (k &rest ls) (edb--1D! database k ls))) (P! :tagged-read-kargs ;; trx (concat "^" (D :pre-tag-regexp) "\\([" (D :tag-chars) "]*\\)" (D :separator-regexp)) ;; crx (D :continuation-regexp) ;; pre (D :pre-parse-thunk) ;; t2f (let ((ht (make-hash-table :test 'equal :size (length fspecs))) tag field) (dolist (spec fspecs) (when (setq tag (cadr spec)) (setq field (car spec)) (puthash tag (if (consp field) (car field) field) ht))) ht) ;; default-field (D :default-field)) (P! :tagged-write-kargs ;; pre (D :pre-write-function) ;; sep (D :separator-output) ;; contin (D :continuation-output) ;; all (loop with nam with tag with nm2no = (edb--1D database :nm2no) with fno for spec in fspecs if (setq tag (cadr spec)) collect (progn (setq nam (car spec) fno (gethash (if (consp nam) (car nam) nam) nm2no)) (vector tag fno (aref (db-rs-slice database 'edb--1rs-actual->stored) fno)))) ;; aft (D :post-write-function))))))) (defun db-tagged-convert/index () (let ((details (edb--1D database :tagged-details))) (macrolet ((D (k) `(gethash ,k details))) ;; Work with actual objects. (when (and (D :tagged-field-spec) (not (D :converted-p))) (database-stored->actual database) (setf (D :converted-p) t)) ;; Do any user indexing. (let ((fn (D :index-function))) (when fn (funcall fn database))) ;; Clean up ourselves. (remove-hook 'db-after-read-hooks 'db-tagged-convert/index)))) (defun db-tagged-read (trx crx pre t2f default-field) (when pre (funcall pre)) (goto-char (point-min)) (let (pl nam fld prev) (while (not (eobp)) (unless (looking-at trx) (error "Unexpected end of record (position %d)" (point))) (setq nam (match-string 1) fld (gethash nam t2f)) (end-of-line) (let ((val (buffer-substring (match-end 0) (point)))) (unless (eobp) (forward-char 1)) (while (looking-at crx) (end-of-line) (setq val (concat val "\n" (buffer-substring (match-end 0) (point)))) (forward-line 1)) (when (null fld) ;; Should allow an escape hook here, and provide a ;; generic one that adds to an alist-like entry (db-message "Invalid field name `%s'" nam) (setq fld default-field)) (setq prev (plist-get pl fld)) (when fld (setq pl (plist-put pl fld (if (null prev) val (concat prev "\n" val))))))) pl)) (defun db-tagged-write (record pre sep contin all aft) (when pre (funcall pre record)) (let (tag fno a->s v val i cnt j) (dolist (vec all) (setq tag (aref vec 0) fno (aref vec 1) a->s (aref vec 2) v (aref record fno) val (if a->s (funcall a->s v) v)) (unless (= 0 (length val)) (setq i 0 cnt (if (equal "" tag) sep contin)) (insert tag sep) (while (setq j (string-match "\n" val i)) (insert (substring val i j) "\n" cnt) (setq i (+ j 1))) (insert (substring val i) "\n")))) (delete-char -1) ; HACK: punt last newline; ; it will be added back later. (when aft (funcall aft record))) (provide 'db-tagged) ;;; db-tagged.el ends here edb-1.31/lisp/db-two-dbs.el0000444000175000017500000002700610745616666013643 0ustar ttnttn;;; db-two-dbs.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Support for actions on two databases. ;;; Code: (eval-when-compile (require 'cl)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Process two databases ;;; ;;;###autoload (defun db-process-two-databases (db1 db2 lone1 lone2 corr &optional orderer) (db-with-orderer db1 (unless (database-ordered-p db1 orderer) (db-message "Sorting %S..." (database-print-name db1)) (database-sort db1 orderer)) (unless (database-ordered-p db2 orderer) (db-message "Sorting %S..." (database-print-name db2)) (database-sort db2 orderer)) ;; Perhaps check for identical keys here. (db-message "Databases are properly ordered") (let* ((rno1 (edb--1D db1 :nrecords)) (vov1 (edb--1D db1 :vov)) (zix1 0) (rno2 (edb--1D db2 :nrecords)) (vov2 (edb--1D db2 :vov)) (zix2 0) (done1 (= 0 rno1)) (done2 (= 0 rno2)) r1 r2 r-order) (while (not (or done1 done2)) (setq r1 (aref vov1 zix1) r2 (aref vov2 zix2) r-order (funcall orderer r1 r2)) (cond ((= -1 r-order) (funcall lone1 r1) (incf zix1) (when (= zix1 rno1) (setq done1 t))) ((= 1 r-order) (funcall lone2 r2) (incf zix2) (when (= zix2 rno2) (setq done2 t))) ((= 0 r-order) (funcall corr r1 r2) (incf zix1) (incf zix2) (when (= zix1 rno1) (setq done1 t)) (when (= zix2 rno2) (setq done2 t))) (t (error "Bad result %s from orderer." r-order)))) (while (not done1) (funcall lone1 (aref vov1 zix1)) (incf zix1) (when (= zix1 rno1) (setq done1 t))) (while (not done2) (funcall lone2 (aref vov2 zix2)) (incf zix2) (when (= zix2 rno2) (setq done2 t))) nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Merge ;;; ;; Want to display both records in full and, for each differing field, ;; ask how to set the merged database: from one, from the other, or by ;; entering something particular. It should also be possible to edit ;; the merged record before proceeding to the next one. ;; Should check for the consistency of the two databases. Should permit ;; conversion for one or both databases as part of this procedure. ;;;###autoload (defun db-merge () "Merge two databases chosen with completion among read-in databases." (interactive) (let ((avail (mapcar (lambda (db) (cons (database-print-name db) db)) (edb--1all-known-databases))) db1 db2 db3 buf1 buf2 buf3) (cond ((< (length avail) 2) (error "Less than two read-in databases.")) ((= 2 (length avail)) (setq db1 (cdar avail) db2 (cdadr avail))) (t ;; Could check that a data display buffer exists. (setq db1 (assoc (completing-read "First database to merge? [? for options] " avail nil t nil) avail)) (setq avail (delq db1 avail)) (setq db1 (cdr db1)) ;; fixme: err if not compatabile. (setq db2 (cdr (assoc (completing-read "Second database to merge? [? for options] " avail nil t nil) avail))))) (setq buf1 (car (edb--1D db1 :ddbufs)) buf2 (car (edb--1D db2 :ddbufs))) (setq db3 (let ((result (edb--copy-v1-monolithic-mess db1))) (callf2 concat "Copy of " (database-print-name db1)) (edb--1D! result :vov nil) ; hmmm (edb--1D! result :nrecords 0) ;; Should this go after db-choose-format-file? (edb--1D! result :file (concat (edb--1D db1 :file) "-COPY")) (edb--1D! result :ddbufs (list (db-setup-data-display-buffer (db-choose-format-file result nil nil) result t))) result) buf3 (car (edb--1D db3 :ddbufs))) (setf (database-print-name db3) (concat "Merge of `" (database-print-name db1) "' and `" (database-print-name db2) "'")) (let ((idx1 (with-current-buffer buf1 (edb--S :index))) (idx2 (with-current-buffer buf2 (edb--S :index)))) (delete-other-windows) (switch-to-buffer buf1) (split-window-vertically (/ (window-height) 2)) (other-window 1) (switch-to-buffer buf2) (split-window-vertically) (other-window 1) (switch-to-buffer buf3) (set-buffer buf1) (db-process-two-databases db1 db2 (lambda (r) (database-add-record r db3)) (lambda (r) (database-add-record r db3)) (lambda (r1 r2) (database-add-record (db-merge-records r1 r2 db3 buf1 buf2 buf3) db3))) (db-in-buffer buf1 (db-jump-to-record idx1)) (db-in-buffer buf2 (db-jump-to-record idx2)) (db-in-buffer buf3 (db-jump-to-record 1)))) (message "Done merging.")) (defun db-merge-records (r1 r2 db buf1 buf2 buf3) (if (equal r1 r2) r1 (set-buffer buf1) (db-display-record r1 t) (set-buffer buf2) (db-display-record r2 t) (set-buffer buf3) (let* ((nfields (length (database-fieldnames db))) (r3 (make-vector nfields nil)) (ds1-all (with-current-buffer buf1 (edb--S :displayspecs))) (ds2-all (with-current-buffer buf2 (edb--S :displayspecs))) (cffuncs-slice (db-rs-slice db 'edb--1rs-common-form-function)) v1 v2 ds1 ds2 cf fname) (dotimes (fno nfields) (setq ds1 (aref ds1-all fno) ds2 (aref ds2-all fno) cf (or (aref cffuncs-slice fno) 'identity) v1 (funcall cf (aref r1 fno)) v2 (funcall cf (aref r2 fno))) (if (equal v1 v2) (aset r3 fno v1) (setq fname (db-fname<-fno fno db)) ;; Problem: nil might not be valid in some places. ;; For now, ignore that. (db-display-record r3 t fno) ;; Does no constraint checking; is this the right thing to do? ;; Help for one-char-question is not entirely satisfactory here. (aset r3 fno (cond ((y-or-n-p (format "Use first value for %s field? [%s] " fname (db-callconvert (edb--1ds-actual->display ds1) v1 nil nil))) v1) ((y-or-n-p (format "Use second value for %s field? [%s] " fname (db-callconvert (edb--1ds-actual->display ds2) v2 nil nil))) v2) (t (unless (equal (edb--1ds-display->actual ds1) (edb--1ds-display->actual ds2)) (error "Unequal display->actual functions")) (db-callconvert (edb--1ds-display->actual ds1) (read-from-minibuffer (format "Enter value for %s field: " fname)) nil nil nil)))))) r3))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Compare ;;; ;;;###autoload (defun databases-compatible (db1 db2) "Return t if the database records have the same field names and type, nil otherwise." ;; Should eventually check types as well. (let ((rv t) (fno 0) (count1 (length (database-recordfieldspecs db1))) (count2 (length (database-recordfieldspecs db2))) (types1-slice (db-rs-slice db1 'edb--1rs-type)) (types2-slice (db-rs-slice db2 'edb--1rs-type))) (when (= count1 count2) (while (and rv (< fno count1)) (setq rv (eq (aref types1-slice fno) (aref types2-slice fno))) (incf fno)) rv))) (defun database-compare-hack (db1 db2) ;; Check that fieldnames and types are the same. (unless (databases-compatible db1 db2) (error "Incompatible databases.")) (let* ((name1 (or (database-print-name db1) "First Database")) (name2 (or (database-print-name db2) "Second Database")) (loners1 (get-buffer-create (concat "Loners for " name1))) (loners2 (get-buffer-create (concat "Loners for " name2))) (discrep (get-buffer-create (concat "Discrepancies between " name1 " and " name2)))) (dolist (buf (list loners1 loners2 discrep)) (with-current-buffer buf (erase-buffer))) (flet ((print-r (r db) (let ((names (database-fieldnames db))) (princ "\n") (dotimes (fno (length (database-fieldnames db))) (princ (format "%s: %s\n" (aref names fno) (aref r fno)))))) (print-l1 (r) (db-in-buffer loners1 (print-r r db1))) (print-l2 (r) (db-in-buffer loners2 (print-r r db2)))) (db-process-two-databases db1 db2 'print-l1 'print-l2 (lambda (r1 r2) ;; We already know that order-function considers the two ;; records the same; now we need to check whether any of ;; their fields differ and if so, report it. (unless (equal r1 r2) (db-in-buffer discrep (let ((all-rs (edb--1D db1 :elaborated-rfspecs)) fname rs ofunc v1 v2) (princ "\n") (dotimes (fno (length (database-fieldnames db1))) (setq fname (db-fname<-fno fno db1) ofunc (db-rs-ordfunc (aref all-rs fno)) v1 (aref r1 fno) v2 (aref r2 fno)) (cond ((equal v1 v2) (princ (format " %s: %s\n" fname v1))) ((and ofunc (zerop (funcall ofunc v1 v2))) (princ (format ". %s: %s\n. %s: %s\n" fname v1 fname v2))) (t (princ (format "* %s: %s\n* %s: %s\n" fname v1 fname v2))))))))))))) (provide 'db-two-dbs) ;;; db-two-dbs.el ends here edb-1.31/lisp/db-types.el0000444000175000017500000005102710745616666013430 0ustar ttnttn;;; db-types.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Library of types for EDB database fields. ;; This file contains predefined types. For efficiency, they're defined ;; in terms of the displayspec abstraction instead of via format strings. ;; Improvements and additions are welcome. Predefined types for dates and ;; times can be found in db-time.el. ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Contents ;;; ;;; Contents ;;; Variables ;;; Displaytype ;;; Enumeration Displaytypes ;;; Numbers ;;; Booleans ;;; Strings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Variables ;;; (:edb1 :1displaytypes (make-hash-table :test 'eq)) (:edb1 :1recordfieldtypes (make-hash-table :test 'eq)) (defvar db-enum-ignore-case t "If non-nil, assume that any association lists created from enumeration types input names are to include both upper and lower case versions of the name, if distinct.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Displaytype ;;; ;;;###badname (defalias 'define-displaytype-from-displayspec 'edb-define-displaytype) (put 'edb-define-displaytype 'lisp-indent-hook 2) (defun edb-define-displaytype (name source &rest override) "Define a displaytype NAME (a symbol) with SOURCE. SOURCE may be a displayspec, the name (a symbol) of a currently defined type, or nil. In all cases, a new displayspec object is created and then modified by OVERRIDE, a sequence of alternating keywords and values, and finally added to a global list. Return NAME." (unless (symbolp name) (error "Not a symbol: %s" name)) (let ((ds (cond ((edb--1ds-p source) (edb--copy-1ds source)) ((not source) (apply 'edb--make-1ds override)) ((and (symbolp source) (let ((ds (db-dspec<-dtype source))) (when ds (edb--copy-1ds ds))))) (t (error "Not a displayspec or known displaytype: %s" source))))) (when override (let ((ls override) (kwidx (get 'edb--1ds 'kwidx))) (while ls (aset ds (or (cdr (assq (car ls) kwidx)) (error "No such keyword: %s" (car ls))) (cadr ls)) (setq ls (cddr ls))))) (puthash name ds (edb--G :1displaytypes)) name)) ;;;###badname (defalias 'define-recordfieldtype-from-recordfieldspec 'edb-define-recordfieldtype) (put 'edb-define-recordfieldtype 'lisp-indent-hook 2) (defun edb-define-recordfieldtype (name source &rest override) "Define a recordfieldtype NAME (a symbol) with SOURCE. SOURCE may be a recordfieldspec, the name (a symbol) of a currently defined type, or nil. In all cases, a new recordfieldspec object is created and then modified by OVERRIDE, a sequence of alternating keywords and values, and finally added to a global list. Return NAME." (unless (symbolp name) (error "Not a symbol: %s" name)) (let ((rs (cond ((edb--v1-rs-p source) (edb--copy-v1-rs source)) ((not source) (apply 'edb--make-v1-rs override)) ((and (symbolp source) (let ((rs (db-rfspec<-rftype source))) (when rs (edb--copy-v1-rs rs))))) (t (error "Unknown recordfieldspec or recordfieldtype: %s" source))))) (when override (let ((ls override) (kwidx (get 'edb--v1-rs 'kwidx))) (while ls (aset rs (or (cdr (assq (car ls) kwidx)) (error "No such keyword: %s" (car ls))) (cadr ls)) (setq ls (cddr ls))))) (puthash name rs (edb--G :1recordfieldtypes)) name)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Enumeration displaytypes ;;; ;; An enumeration displaytype is used for fields whose values are one of a ;; fixed set of alternatives. ;; For each alternative, four pieces of information are specified ;; (see documentation for `define-enum-type' for details). We have the ;; following options for storing the relationships between those pieces of ;; information, which must be used by such functions as the displayspec's ;; display->actual function: ;; * in global variables keyed by enum-type name and looked up when needed, ;; * in database-local variables similar to the above, or ;; * in the functions themselves (the functions are created when the ;; enum-type is defined and must in any event contain some specific ;; information such as the enum-type name). ;; Where to Keep Info: If any of the information is kept in database-local ;; variables, all of it should be, because database-local variables are ;; saved when the database is stored in internal file layout and restored ;; when it is read in again. However, other information is kept in global ;; variables such as :1displaytypes, so it is problematic to keep any ;; information in database-local variables; it is especially bad to have ;; the type half-defined so that an error is produced if the type is ;; redefined but the existing information is insufficient to provide the ;; full enum type functionality. If all the information is stored in ;; database-local variables, then it is unnecessary for databases stored in ;; internal file layout to have calls to define-enum-type in their ;; auxiliary files. ;;;###badname (defalias 'define-enum-type 'edb-define-enumtype) (defun edb-define-enumtype (typename alternatives &optional optstring) "Make TYPENAME (a symbol or string) an enumerated type. Both a displaytype and a recordfieldtype are created. ALTERNATIVES is a list. Each alternative is a list of up to four components: the internal representation, any constant Lisp object, often a string; the input representation typed by the user to specify this alternative, a string or list of strings (for multiple input representations); the display representation, a string; and the file storage representation, a string. If the input representation is omitted and the internal representation is a string, that string is used. If the display representation is omitted, it defaults to the first input representation. The display representation is automatically also a valid input representation. If the file storage representation is omitted, it defaults to the display representation. If all the other components are omitted, the internal representation string may be used in place of a one-element list containing just it. Optional argument OPTSTRING is a displayspec option string." (let ((type (if (stringp typename) (intern typename) typename)) d->a dinput->a a->d a->s a-s-differ internal input display storage) (dolist (alt alternatives) (unless (listp alt) (setq alt (list alt))) (setq internal (car alt) input (or (car (cdr alt)) internal) input (if (listp input) input (list input)) display (or (car (cdr (cdr alt))) (car input)) storage (or (nth 3 alt) display) d->a (nconc d->a (mapcar (lambda (irep) (cons irep internal)) input)) a-s-differ (or a-s-differ (not (equal internal storage)))) (unless (member display input) (push (cons display internal) dinput->a)) (push (cons internal display) a->d) (push (cons internal storage) a->s)) ;; The order is significant in db-enum-make-help-info. ;; [It's not clear whether that's a feature or a bug.] (setq d->a (nconc d->a (nreverse dinput->a)) a->d (nreverse a->d) a->s (and a-s-differ (nreverse a->s))) (flet ((enum-do-completions (rep type d->a) ;; Given a string REP and an enum TYPE, return REP if it is a ;; valid input representation, otherwise see if it completes to a ;; valid one, and show the possible completions. (let ((hit (assoc rep d->a))) (if hit (cdr hit) (let* ((completion-ignore-case db-enum-ignore-case) (try (try-completion rep d->a))) (if (and try (setq hit (assoc try d->a))) (cdr hit) (dbf-set-this-field-text (or try "")) (setq rep (completing-read (format "Enter \"%s\" enum value (? for list): " type) d->a nil t (or try ""))) (cdr (assoc rep d->a))))))) (make-enum-member-orderer (type a->d v< v= v>) ;; Given an enum type TYPE, create an ordering function which ;; compares two items in the enum type's alternatives list. The ;; resulting function returns V< if its first argument precedes ;; its second argument in the alternative list, V= if they're ;; equal or neither appears, and V> if the first follows the ;; second. ;; ;; If one of the arguments doesn't appear in the alternatives ;; list, the other is considered to precede it. `(lambda (o1 o2) (if (equal o1 o2) ,v= (let ((ls ',a->d) (rv ,v=) alt-o) (while ls (setq alt-o (car ls)) (cond ((equal (car alt-o) o1) (setq rv ,v< ls nil)) ((equal (car alt-o) o2) (setq rv ,v> ls nil)) (t (setq ls (cdr ls))))) rv))))) (edb-define-displaytype type (db-dspec<-type/opts nil (when optstring (split-string optstring ",")) t) :indent nil :display->actual `(lambda (input-rep) (,(symbol-function 'enum-do-completions) input-rep ',type ',d->a)) :actual->display `(lambda (enum-val) (cdr (assoc enum-val ',a->d)))) (edb-define-recordfieldtype type nil :type type :default-value "" :order-fn (make-enum-member-orderer type a->d -1 0 1) :sort-fn (make-enum-member-orderer type a->d t nil nil) :match-function 'db-string-match-function :help-info (with-temp-buffer (let ((standard-output (current-buffer))) (princ (format "%s: an enumerated type. " type)) (display-completion-list (mapcar 'car d->a)) (buffer-string))) :actual->stored (when a->s `(lambda (enum-val) (cdr (assoc enum-val ',a->s)))) :stored->actual (when a->s `(lambda (stored-val) (car (rassoc stored-val ',a->s)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Numbers ;;; ;;; ;;; Integers ;;; (edb-define-displaytype 'integer nil :indent nil :actual->display 'int-to-string :display->actual 'string-to-int) (edb-define-recordfieldtype 'integer nil :type 'integer :default-value 0 :actual->stored 'int-to-string :stored->actual 'string-to-int :order-fn 'db-number-order :sort-fn '< :match-function '= :help-info "An integer.") (edb-define-displaytype 'integer-or-nil nil :indent nil :actual->display 'db-number-or-nil->string :display->actual 'db-string->integer-or-nil) (edb-define-recordfieldtype 'integer-or-nil nil :type 'integer-or-nil :default-value 0 :actual->stored 'db-number-or-nil->string :stored->actual 'db-string->integer-or-nil :order-fn 'db-number-or-nil-order-nil-greatest ;; :sort-fn '< :match-function 'equal :help-info "An integer, or nil.") ;;; ;;; Numbers (a number is an integer or a float) ;;; (let ((correct-string-to-number ;; Emacs 19.28 bug: isfloat_string fails when arg has trailing spaces, ;; so (s2n "5.4") => 5.4 but (s2n "5.4 ") => 5 . (if (= 5 (string-to-number "5.4 ")) (lambda (string) (if (string-match " " string) ;; chop everything after the first space (string-to-number (substring string 0 (match-beginning 0))) (string-to-number string))) 'string-to-number))) (edb-define-displaytype 'number nil :indent nil :actual->display 'number-to-string :display->actual correct-string-to-number) (edb-define-recordfieldtype 'number nil :type 'number :default-value 0 :actual->stored 'number-to-string :stored->actual correct-string-to-number :order-fn 'db-number-order :sort-fn '< :match-function '= :help-info "A number.")) (edb-define-displaytype 'number-or-nil nil :indent nil :actual->display 'db-number-or-nil->string :display->actual 'db-string->number-or-nil) (edb-define-recordfieldtype 'number-or-nil nil :type 'number-or-nil :default-value 0 :actual->stored 'db-number-or-nil->string :stored->actual 'db-string->number-or-nil :order-fn 'db-number-or-nil-order-nil-greatest ;; :sort-fn '< :match-function 'equal :help-info "A number, or nil.") ;;; ;;; Sorting and ordering ;;; (defsubst db-number-order (a b) "Return -1, 0, or 1 depending on whether A < B, A = B, or A > B." (cond ((= a b) 0) ((< a b) -1) (t 1))) (defun db-number-or-nil-order-nil-greatest (a b) "Like db-number-order, but nil is treated as greater than any integer. This puts nil after integers in an increasing list." (cond ((and a b) (db-number-order a b)) (a -1) (b 1) (t 0))) (defun db-number-or-nil-order-nil-least (a b) "Like db-number-order, but nil is treated as smaller than any integer. This puts nil after integers in a decreasing list." (cond ((and a b) (db-number-order a b)) (a 1) (b -1) (t 0))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Booleans ;;; (edb-define-displaytype 'yes-no nil :indent nil :min-width 3 :max-width 3 :actual->display 'db-boolean->yes-no-string :display->actual 'db-yes-no-string->boolean) (edb-define-recordfieldtype 'boolean nil :type 'boolean :default-value nil :actual->stored 'db-boolean->yn-string :stored->actual 'db-yn-string->boolean :order-fn 'db-boolean-order-function :sort-fn 'db-boolean-lessp :match-function 'eq :help-info "A boolean value.") (defsubst db-boolean->yes-no-string (b) (if b "Yes" "No")) (defun db-yes-no-string->boolean (s) (let ((low (downcase s))) (cond ((string= "yes" low) t) ((string= "no" low) nil) (t (error "`%s' is not `Yes' or `No'." s))))) (defsubst db-boolean->yn-string (b) (if b "Y" "N")) (defsubst db-yn-string->boolean (s) (string= "y" (downcase s))) (defun db-boolean-order-function (b1 b2) ;; NOTE: t < nil so that in the "increasing" ordering "true" things occur ;; before false ones. (This is somewhat arbitrary.) (cond ((or (and b1 b2) (not (or b1 b2))) 0) (b1 -1) (t 1))) (defsubst db-boolean-lessp (b1 b2) (and (not b1) b2)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Strings and variants ;;; ;; Type: string (edb-define-displaytype 'string nil :max-height nil :indent t :match-actual->display 'db-string-match-actual->display :match-display->actual 'db-string-match-display->actual) (edb-define-recordfieldtype 'string nil :type 'string :default-value "" :order-fn 'db-string-order-ci :sort-fn 'db-string-lessp-ci :match-function 'db-string-match-function :help-info "A string.") ;; Type: one-line-string (edb-define-displaytype 'one-line-string 'string :min-height 1 :max-height 1 :indent nil) (edb-define-recordfieldtype 'one-line-string 'string :type 'one-line-string) ;; Type: string-or-nil (edb-define-displaytype 'string-or-nil 'string :actual->display 'db-string-or-nil->string) (edb-define-recordfieldtype 'string-or-nil 'string :type 'string-or-nil :order-fn 'db-string-or-nil-order-ci :sort-fn 'db-string-or-nil-lessp-ci :match-function 'db-string-or-nil-match-function) ;; Type: nil-or-string (edb-define-displaytype 'nil-or-string 'string-or-nil :display->actual 'db-string->nil-or-string) (edb-define-recordfieldtype 'nil-or-string 'string-or-nil :type 'nil-or-string) ;; Type: one-line-string-or-nil (edb-define-displaytype 'one-line-string-or-nil 'one-line-string :actual->display 'db-string-or-nil->string) (edb-define-recordfieldtype 'one-line-string-or-nil 'one-line-string :type 'one-line-string-or-nil :order-fn 'db-string-or-nil-order-ci :sort-fn 'db-string-or-nil-lessp-ci :match-function 'db-string-or-nil-match-function) ;; Helping functions for type string (defsubst db-string-lessp-ci (s1 s2) "Case-insensitive version of string-lessp." (let ((v (compare-strings s1 0 nil s2 0 nil t))) (when (numberp v) (> 0 v)))) (defun db-string-order-ci (s1 s2) "Return -1, 0, or 1 depending on whether string S1 is lexicographically less than, equal to, or greater than S2. Case-insensitive." (let ((v (compare-strings s1 0 nil s2 0 nil t))) (cond ((eq t v) 0) ((> 0 v) -1) (t 1)))) ;;; Matching strings ;; Pattern is a list of 'regexp and a regexp or a list of 'string, a ;; regexp, and a string. (defun db-make-regexp-pattern (rx) (list 'regexp rx)) (defun db-regexp-pattern-regexp (pat) (car (cdr pat))) (defun db-make-string-pattern (s &optional rx) (list 'string (or rx (regexp-quote s)) s)) (defun db-string-pattern-regexp (pat) (car (cdr pat))) (defun db-string-pattern-string (pat) (car (cdr (cdr pat)))) (defsubst db-string-match-function (pat s) ;; The second element of pat is a regexp whether the pat is a ;; string or a regexp. (string-match (if (stringp pat) ; slack: handle string pat (car (cdr pat))) s)) (defun db-string-match-display->actual (s) ;; Return a pattern. (if (string-match "^[ \t]*\\(/\\|regexp[ \t]+\\)" ;;; was: dbm-string-regexp-prefix s) (db-make-regexp-pattern (substring s (match-end 0))) (db-make-string-pattern s))) (defun db-string-match-actual->display (pat) (cond ((eq (car pat) 'string) (db-string-pattern-string pat)) ((eq (car pat) 'regexp) (concat "/" ;;; was: dbm-string-regexp-prefix-string (db-regexp-pattern-regexp pat))) (t (error "db-string-match-actual->display: bad pat %s" pat)))) ;; Helping functions for type string-or-nil (defsubst db-string-or-nil->string (s-o-n) (or s-o-n "")) (defsubst db-string-or-nil-lessp-ci (x y) (db-string-lessp-ci (db-string-or-nil->string x) (db-string-or-nil->string y))) (defsubst db-string-or-nil-order-ci (x y) (db-string-order-ci (or x "") (or y ""))) (defsubst db-string-or-nil-match-function (pat s-o-n) (string-match (if (stringp pat) pat (if pat (car (cdr pat)) "")) (or s-o-n ""))) ;; Helping functions for type nil-or-string (defsubst db-string->nil-or-string (s) (if (equal "" s) nil s)) ;;; db-types.el ends here edb-1.31/lisp/db-util.el0000444000175000017500000003325310745616666013242 0ustar ttnttn;;; db-util.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Lisp utilities. ;; This file is largely cannibalized from util-mde.el and util-mdecl.el, ;; which are available from theory.lcs.mit.edu:/pub/emacs/. ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Database messages ;;; (defun db-message (fmtstr &rest args) ;; Format message, display it, and log it in buffer *Database-Log*. (let ((formatted (apply 'format fmtstr args))) (with-current-buffer (get-buffer-create "*Database-Log*") (buffer-disable-undo) (goto-char (point-max)) (insert formatted "\n")) (message "%s" formatted))) (defmacro db-warning (fmtstr &rest args) `(db-message ,(concat "Warning: " fmtstr) ,@args)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Searching, matching, and replacing ;;; (defun db-unused-char-in-buffer () "Return a character not used in the current buffer, or nil. This function attempts to return a character that can be displayed in a single screen column." (save-excursion (let ((maybe 32) (rv t)) (while (eq rv t) (goto-char (point-min)) (if (not (search-forward (char-to-string maybe) nil t)) (setq rv maybe) (setq maybe (% (1+ maybe) 256)) (when (eq maybe 32) (setq rv nil)))) rv))) (defun db-unused-char-in-string (s) "Return a character not used in string S, or nil. This function attempts to return a character that can be displayed in a single screen column." (with-temp-buffer (insert s) (db-unused-char-in-buffer))) ;;; Skipping (defsubst db-skip-string-forward (s) (or (string= "" s) (let* ((beg (point)) (len (length s)) (end (+ beg len))) (when (and (<= end (point-max)) (string= s (buffer-substring-no-properties beg end))) (forward-char len) t)))) (defsubst db-skip-string-backward (s) (or (string= "" s) (let* ((end (point)) (len (length s)) (beg (- end len))) (when (and (<= (point-min) beg) (string= s (buffer-substring-no-properties beg end))) (forward-char (- len)) t)))) (defsubst db-skip-regexp-forward (rx) "If point is at regexp RX, move past it and return point; otherwise return nil." (when (looking-at rx) (goto-char (match-end 0)))) ;; From Robert Potter (defun db-looking-back-at (rx) "Return t when text before point matches regular expression RX." (save-excursion (save-restriction (narrow-to-region (point-min) (point)) (re-search-backward (concat "\\(" rx "\\)\\'") (point-min) t)))) (defun db-how-many-string-overlapping (s) "Return number of matches for string S following point, including overlapping ones." (let ((count 0)) (save-excursion (while (search-forward s nil t) (goto-char (1+ (match-beginning 0))) (incf count))) count)) (defun db-how-many-substring-overlapping (small big) "Return number of matches for SMALL in BIG (both strings), including overlapping ones." (let ((rx (regexp-quote small)) (count 0) (start -1)) (while (setq start (string-match rx big (1+ start))) (incf count)) count)) (defun db-find-char (c s &optional count) "Look for char C in string S; return first index in S whose element is C. If optional arg COUNT is specified, return the COUNTth occurrance." (unless count (setq count 1)) (let ((idx 0) (len (length s)) rv) (while (and (< idx len) (not rv)) (when (char-equal c (aref s idx)) (if (= count 1) (setq rv idx) (decf count))) (incf idx)) rv)) (defun db-find-char-from-end (c s &optional count) "Look for char C in string S; return last index in S whose element is C. Optional arg COUNT means return the COUNTth occurrance from the end." (unless count (setq count 1)) (let ((idx (1- (length s))) rv) (while (and (> idx -1) (not rv)) (when (char-equal c (aref s idx)) (if (= count 1) (setq rv idx) (decf count))) (decf idx)) rv)) (defsubst db-string-trim-whitespace (s) "Return a substring of S with whitespace removed from beginning and end." (let* ((beg (when (string-match "\\`[ \t\n\f\r]+" s) (match-end 0))) (end (string-match "[ \t\n\f\r]+\\'" s (or beg 0)))) (if (or beg end) (substring s (or beg 0) end) s))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Variables ;;; (defun edb--G (key) (edb--rget '(:edb1) key)) (defun edb--G! (key value) (edb--rput '(:edb1) key value)) (:edb1 :bprops (make-hash-table :size 11 :test 'eq :weakness 'key)) ;; Cache for buffer-local control properties hash table. (defvar edb--bprops nil) (defmacro edb--S (property) `(gethash ,property edb--bprops)) (defmacro edb--S! (property newvalue) `(puthash ,property ,newvalue edb--bprops)) (defun edb-get (property &optional buffer) (unless (let* ((single (edb--rget '(:edb1 :schema-schema) 'single)) (runtime (cdr (assq :runtime-keys single)))) (memq property runtime)) (error "Bad property: %S" property)) (if buffer (edb--rget (list :edb1 :bprops buffer) property) (edb--S property))) (defun edb-put (property newvalue &optional buffer) (unless (let* ((single (edb--rget '(:edb1 :schema-schema) 'single)) (runtime (cdr (assq :runtime-keys single)))) (memq property runtime)) (error "Bad property: %S" property)) (if buffer (edb--rput (list :edb1 :bprops buffer) property newvalue) (edb--S! property newvalue))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Files ;;; (defun db-locate-readable-file-prefer-cwd (filename path &optional suffixes) "Return the full path of a readable file named FILENAME, located in `default-directory' or on PATH, a list of directories (strings). Optional arg SUFFIXES is a list of suffixes to append to FILENAME when searching." (setq path (cons default-directory path)) ;; The following is more or less equivalent to: ;; (locate-file filename path suffixes 'readable) ;; but `locate-file' is not yet (2005-01-18) widely available. (catch 'full (dolist (dir path) (unless dir (setq dir default-directory)) (dolist (suf (or suffixes '(""))) (let ((try (expand-file-name (concat filename suf) dir))) (when (file-readable-p try) (throw 'full try))))) nil)) (defun db-same-file-p (n1 n2) "Return t if N1 and N2 are names for the same file. Return nil if neither N1 nor N2 names an existing file." (setq n1 (file-chase-links n1) n2 (file-chase-links n2)) (or (equal n1 n2) (equal n1 (file-name-nondirectory n2)) (equal n2 (file-name-nondirectory n1)) (and (file-exists-p n1) (file-exists-p n2) (equal (file-attributes n1) (file-attributes n2))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Conversion ;;; ;; string-to-int is unacceptable because it returns 0 for unparseable values. (defun db-string->integer-or-nil (s) (let ((rv (condition-case nil (car (read-from-string s)) (error nil)))) (and (integerp rv) rv))) (defalias 'db-string->number-or-nil 'db-string->integer-or-nil) (defun db-string->integer (s) "Return the integer represented by string S, or err." (or (db-string->integer-or-nil s) (error "db-string->integer: `%s' doesn't look like an integer." s))) (defalias 'db-string->number 'db-string->integer) (defun db-number-or-nil->string (n) (if (numberp n) (number-to-string n) "")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Buffers ;;; (defmacro db-in-buffer (buffer &rest body) ;; This macro, which works when body moves point in a buffer ;; displayed in a window other than the selected window, is from ;; Joe Wells . (If Lisp code moves point in a ;; buffer displayed in a window other than the selected window, ;; Emacs kindly restores point in the buffer to its window's ;; version of point.) (declare (indent 1) (debug (form body))) `(let ((targ ,buffer) (this-buffer (current-buffer)) (db-in-buffer-thunk (lambda () ,@body))) (if (eq targ this-buffer) (funcall db-in-buffer-thunk) ;; Can't use save-excursion here because we only want to save the ;; current buffer, not its value for point. (unwind-protect (progn (set-buffer targ) (let* ((w (get-buffer-window targ)) (trackp (and (not (eq w (selected-window))) (eq (window-point w) (point))))) (prog1 (funcall db-in-buffer-thunk) (when (and trackp (eq (current-buffer) targ) (eq w (get-buffer-window targ)) (not (eq w (selected-window)))) (set-window-point w (point)))))) (if (and (bufferp this-buffer) (buffer-name this-buffer)) (set-buffer this-buffer)))))) (defun db-copy-buffer-local-variables (buf &rest exclude) "Copy the values of most of BUF's local variables into the current buffer. The var `enable-multibyte-characters' is handled by `set-buffer-multibyte' and `buffer-undo-list' is excluded along with any of the other variable names \(symbols\) listed in EXCLUDE." (let (symbol value) (dolist (pair (with-current-buffer buf (buffer-local-variables))) (unless (or (atom pair) (memq (setq value (cdr pair) symbol (car pair)) exclude)) (case symbol ((0 nil buffer-undo-list)) ; do nothing (enable-multibyte-characters (set-buffer-multibyte value)) (t (set (make-local-variable symbol) value))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Strings ;;; (defun db-string-split-last-word (s &optional butnot) "Return list of two strings (all-but-last-word last-word). If there is only one word, return (S \"\"). The result strings can be concatenated to return the original string, with the exception of some number (at least one) of spaces and tabs, and possibly a comma immediately preceding them. Optional arg BUTNOT, if non-nil, is a regexp (containing spaces or tabs) which, if found at the end of S, should be considered a single word." (if (let ((delim ",?[ \t]+")) (or (and butnot (string-match (concat delim "\\(" butnot "\\)$") s)) (string-match (concat delim "\\([a-zA-Z0-9'-]+\\)$") s))) (list (substring s 0 (match-beginning 0)) (substring s (match-beginning 1))) (list s ""))) (defun db-string-split-first-word (s) "Return list of strings (first-word remaining-words). String S is split at the first sequence of spaces and tabs." (if (string-match "[ \t]+" s) (list (substring s 0 (match-beginning 0)) (substring s (match-end 0))) (list s ""))) (defun db-count-newlines (s) "Return the number of newline characters found in string S." (let ((rv 0)) (dotimes (idx (length s)) (when (char-equal ?\n (aref s idx)) (incf rv))) rv)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Cursor movement ;;; (defun db-forward-line-wrapping (arg) "Like forward-line, but wrap around to the beginning of the buffer if it encounters the end." (interactive "p") (let ((left (forward-line arg))) (cond ((or (> left 0) (not (bolp))) (goto-char (point-min)) (db-forward-line-wrapping left)) ((< left 0) (goto-char (point-max)) (db-forward-line-wrapping (1+ left)))))) (defun db-current-line () "Return the line number of the line containing point." (save-restriction (widen) (save-excursion (beginning-of-line) (1+ (count-lines 1 (point)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; File local variables ;;; (defun edb-true (&rest args) "Return t unconditionally, no matter the ARGS." t) (defun edb-hookp (val) "Return t if VAL appears to be a hook. That is, if it is satisfies `functionp', or it is a list of elements each of which is either t or satisfies `functionp'." (or (functionp val) (and (consp val) (equal (make-list (length val) t) (mapcar (lambda (v) (or (eq t v) (functionp v))) val))))) (defun db-really-hack-local-variables () "Like `hack-local-variables', but without inhibitions." (let ((enable-local-eval t) (enable-local-variables t)) (hack-local-variables))) ;;; db-util.el ends here edb-1.31/lisp/edb-1int-to-single.el0000444000175000017500000003003010745370012015150 0ustar ttnttn;;; edb-1int-to-single.el ;; Copyright (C) 2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; This file provides the single command `edb-1int-to-single', ;; as well as the feature by the same name. See info file. ;;; Code: (eval-when-compile (require 'cl)) (require 'edbcore) (defun edb-1int-to-single (filename) "Translate contents of FILENAME to a \"single\" schema-schema. If the contents are not in EDB 1.x \"internal file layout, format 0.7\", signal an error. Otherwise, leave the result of the translation in a newly created output buffer named \":EDB (single) from FILENAME\". The output buffer may have several \"\" tokens in it, indicating places where further attention (a nice way to say \"manual tweaking\") is required to complete the translation. See info node `(edb)edb-1int-to-single' for the complete list of possible occurances and suggested remedies." (interactive "fTranslate EDB 1.x \"internal file layout\": ") (let ((fixme "") ;; todo: for EDB 2.x, replace computation w/ (its) constant value (mm-idx (let ((slots (mapcar (lambda (ent) (intern (format ":%s" (car ent)))) (get 'edb--v1-monolithic-mess 'cl-struct-slots)))) (map 'list 'cons slots (number-sequence 0 (length slots))))) mm extra records coding loc-block locals) (flet ((elm () (let ((emacs-lisp-mode-hook nil)) (emacs-lisp-mode))) (mref (slot) (aref mm (cdr (assq slot mm-idx)))) (cprop (prop &optional more) (insert (format "%s" prop) (if more (format " %S" more) "") "\n")) (nlnl (&optional stuff) (insert (if stuff (format "%s" stuff) "") "\n\n")) (nl () (insert "\n")) (backslash-hat (c) (cond ((= ?\n c) (insert c)) ((> 32 c) (insert "\\^" (+ c 64))) (t (insert c))))) (with-temp-buffer (elm) (insert-file-contents filename) (goto-char (point-min)) (unless (looking-at ";; Database file written by EDB; format 0.7") (error "Not in \"internal file layout, format 0.7\": %s" filename)) (forward-line 1) (setq mm (read (current-buffer)) extra (read (current-buffer)) records (buffer-substring-no-properties (progn (forward-line 1) (point)) (point-max)) coding coding-system-for-read)) (switch-to-buffer (generate-new-buffer (concat ":EDB (single) from " filename))) (buffer-disable-undo) (setq default-directory (file-name-directory filename)) (elm) (let ((standard-output (current-buffer)) v) (insert ":EDB (single) ;;; -*- mode:emacs-lisp; coding:") (princ (or coding fixme)) (nlnl "; -*-") (cprop :name) (prin1 (or (mref :print-name) fixme)) (nlnl) (cprop :fields) (pp (map 'vector 'cons (mref :fieldnames) (mref :recordfieldspecs))) (nl) (when (setq v (car (mref :field-priorities))) (cprop :field-order) (pp (apply 'vector (flet ((ok (x) (cond ((symbolp x) x) ((numberp x) (aref (mref :fieldnames) x)) (t (error "badness"))))) (mapcar (lambda (spec) (cond ((and (consp spec) (not (consp (cdr spec)))) (ok (car spec))) ((consp spec) (cons (ok (car spec)) (cdr spec))) (t (ok spec)))) v)))) (nl)) (let ((fsub (mref :sub-fieldsep-string)) (rsub (mref :sub-recordsep-string))) (when (or rsub fsub) (cprop :substitution-separators) (let ((standard-output 'backslash-hat)) (pp (vector fsub rsub))) (nl))) (when (setq v (mref :substitutions)) (cprop :substitutions) (let ((standard-output 'backslash-hat)) (pp (apply 'vector v))) (nl)) (let (try limit) (flet ((yes (c) (when c (cprop :display t) (setq limit (+ (cadr (insert-file-contents try)) (point))) (when (re-search-forward "\f*\nLocal Variables:\n" limit 1) (goto-char limit) (setq loc-block (buffer-substring-no-properties (match-end 0) limit)) (delete-region (match-beginning 0) limit)) (unless (bolp) (insert "\n")) t))) (cond ((yes (and (setq try (assq :format-file extra)) (setq try (expand-file-name (cdr try) (file-name-directory filename))) (file-readable-p try)))) ((yes (setq try (db-locate-readable-file-prefer-cwd (file-name-nondirectory (file-name-sans-extension filename)) (cons (file-name-directory filename) db-format-file-path) db-format-file-suffixes)))) (t (cprop :display (list (intern fixme))) (insert fixme "\n")))) (nlnl :EOTB)) (cprop :data '(:coding t :seqr read-line :EOTB ":EOTB")) (insert records ":EOTB") (when loc-block (goto-char (point-min)) (forward-line 1) (insert "\n;;; From primary format file's local variables block:\n") (narrow-to-region (point) (point-max)) (insert loc-block) (delete-region (point) (progn (search-backward "\nEnd:") (1+ (point)))) (narrow-to-region (point-min) (point)) (goto-char (point-min)) (while (< (point) (point-max)) (cond ((looking-at "^eval:") (delete-char 5) (let* ((opoint (point)) (form (read (current-buffer))) (special (assq (car form) '((database-set-fieldnames-to-list "redundant") (dbf-set-summary-format :summary-format car))))) (if special (let* ((why (cadr special)) (blurb (if (stringp why) why (format "%s `%s' %s" "translated to" why "control property"))) (xlat (caddr special))) (delete-region opoint (progn (forward-line 1) (point))) (insert ";;*" blurb ":\n;; " (format "(%s ...)" (car form)) "\n") (when xlat (save-excursion (save-restriction (widen) (re-search-forward "^:data") (beginning-of-line) (cprop why) (let ((standard-output 'backslash-hat) (v (funcall xlat (cdr form)))) (pp v) (if (stringp v) (nlnl) (nl))))))) (goto-char opoint) (delete-horizontal-space) (indent-sexp) (insert ";;*unhandled (" fixme "):\n") (comment-region (point) (progn (forward-sexp 1) (forward-line 1) (point)))))) (t (let* ((opoint (point)) (var (progn (looking-at "\\s-*\\([^:]+\\):\\s-*") (prog1 (intern (match-string 1)) (goto-char (match-end 0))))) (val (prog1 (read (current-buffer)) (forward-line 1))) (form `(set (make-local-variable ',var) ,(if (or (stringp val) (vectorp val)) val (list 'quote val))))) (case var ((db-new-record-function dbf-first-change-function dbf-every-change-function dbf-before-display-record-function dbf-format-name-spec-alist edb-data-coding) (comment-region opoint (point)) (save-excursion (goto-char opoint) (insert ";;*special variable (" fixme "):\n"))) (t (setq locals (acons var val locals)) (delete-region opoint (point)) (insert (format ";;*added to `:locals' %s: %s\n" "control property" var)))))))) (widen) (delete-blank-lines)) (goto-char (point-min)) (when (setq locals (nconc (nreverse locals) (mref :locals))) (re-search-forward "^:data") (beginning-of-line) (cprop :locals) (pp (apply 'vector (mapcar (lambda (pair) (list (car pair) (cdr pair))) locals))) (nl)) (goto-char (point-min)))))) (provide 'edb-1int-to-single) ;;; edb-1int-to-single.el ends here edb-1.31/lisp/edb-meta.el0000444000175000017500000001331510745370012013333 0ustar ttnttn;;; edb-meta.el ;; Copyright (C) 2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; This file provides the single command `edb-meta', ;; as well as the feature by the same name. ;;; Code: (eval-when-compile (require 'cl)) (defun edb-meta () "Summarize EDB state in a new buffer, and switch to it. Display the version number, and `features' related to EDB in parens. Next, display a tree of key/value pairs starting w/ `edb--global-state'. Display each key in `font-lock-builtin-face', abutted to its value. Recursion occurs through hash table values. Here is a list of how objects of various types are represented: hash-table -- # marker -- m vector -- vLEN string -- \"\"LEN symbol -- NAME (as key), or 'NAME (as value) buffer -- (lambda ...) -- (f) compiled-function -- {f} cons -- ()LEN monolithic-mess structure -- [mm: \"NAME\"] displayspec structure -- [ds] recordfieldtype structure -- [rs] LEN is the length of the vector or string or list. `nil' is never shown as a value; absence of a displayed value means the value is `nil'. Unrecognized objects display as \"???\" in `font-lock-warning-face'. Next, display a list of global variables that have non-nil default bindings (either as a variable or as a function). This list is taken from the property `globals-to-check' of symbol `edb-meta'." (interactive) (switch-to-buffer (get-buffer-create "*EDB Meta*")) (buffer-disable-undo) (erase-buffer) (setq major-mode 'edb-meta-mode mode-name "EDB Meta" truncate-lines t) (insert "EDB " edb-version) (let (acc) (dolist (f features) (when (string-match "\\(^database$\\)\\|\\(^edb-\\|^db-\\)" (symbol-name f)) (push f acc))) (insert (format " %s\n" acc))) (flet ((w/face (string face) (propertize string 'face face)) (fo (o &optional keyp) (case (type-of o) (vector (cond ((edb--1ds-p o) "[ds]") ((edb--v1-rs-p o) "[rs]") ((= (length (get 'edb--v1-monolithic-mess 'cl-struct-slots)) (length o)) (format "[mm%s]" (if (stringp (aref o 0)) (format ": %S" (aref o 0)) ""))) (t (format "v%d" (length o))))) (symbol (cond ((not o) "") ((or keyp (keywordp o)) (symbol-name o)) (t (format "'%s" o)))) (hash-table "#") (integer (format "%d" o)) (compiled-function "{f}") (marker "m") (string (format "%S%d" "" (length o))) (buffer (format "<%s>" (buffer-name o))) (cons (if (eq 'lambda (car o)) "(f)" (format "()%d" (safe-length o)))) (t (w/face "???" 'font-lock-warning-face)))) (fk (k) (if (symbolp k) (symbol-name k) (fo k))) (d (level header ht) (let (kids) (insert "\n" (make-string (* 2 level) 32) header) (maphash (lambda (k v) (let ((k-str (fo k t))) (insert " " (w/face k-str 'font-lock-builtin-face) (fo v)) (when (hash-table-p v) (push (cons k-str v) kids)))) ht) (insert "\n") (dolist (kid (nreverse kids)) (d (1+ level) (car kid) (cdr kid)))))) (d 0 (fo 'edb--global-state t) edb--global-state)) (insert "\n") (dolist (sym (get 'edb-meta 'globals-to-check)) (let ((var (and (boundp sym) (symbol-value sym))) (fun (and (fboundp sym) (symbol-function sym)))) (when (or var fun) (insert (if var "(v)" "") (if fun "(f)" "") "\t" (symbol-name sym) "\n")))) (goto-char (point-min)) (set (make-local-variable 'revert-buffer-function) (lambda (ignore-auto-IGNORED noconfirm-IGNORED) (message "Redoing edb-meta...") (edb-meta) (message "Redoing edb-meta... done"))) (buffer-enable-undo)) ;; Some of the following are no longer supported but we check for them anyway; ;; if they are bound, that indicates the program needs to be updated. (put 'edb-meta 'globals-to-check '(db-before-read-hooks db-after-read-hooks db-view-mode-hooks db-edit-mode-hooks database-summary-mode-hooks dbf-enter-field-hook db-tagged-rrfr-hooks db-tagged-wrfr-before-hooks db-tagged-wrfr-after-hooks )) (provide 'edb-meta) ;;; edb-meta.el ends here edb-1.31/lisp/edb-t-human-names.el0000444000175000017500000001103310745616666015074 0ustar ttnttn;;; edb-t-human-names.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Names for human beings ;; ;; These variables and functions used to be in db-types.el, ;; without the "edb-t-human-names:" prefix. ;; ;; TODO: Internationalize (remove/reduce English bias). ;;; Code: ;; ;; Last names ;; (defun edb-t-human-names:order-last-names (n1 n2) "Return -1, 0, or 1 depending on whether last name N1 is lexographically less than, equal to, or greater than N2." ;; Note stringency of equality test: capitalization and spacing matter. (cond ((equal n1 n2) 0) ((string-lessp (edb-t-human-names:canonicalize-name n1) (edb-t-human-names:canonicalize-name n2)) -1) (t 1))) (defun edb-t-human-names:canonicalize-name (s) ;; Remove spaces and quotation marks, and ignore capitalization. (let ((result "")) (while (string-match "[ ']+" s) (setq result (concat result (substring s 0 (match-beginning 0))) s (substring s (match-end 0)))) (downcase (concat result s)))) ;; ;; First names ;; (defconst edb-t-human-names:nicknames '(("Abraham" "Abe") ("Charles" "Charlie") ("David" "Dave") ("Elizabeth" "Beth" "Liz") ("Gerald" "Gerry") ("James" "Jamey" "Jamie") ("Leonard" "Lenny") ("Michael" "Mike") ("Richard" "Dick" "Dicky" "Rick" "Ricky" "Rico") ("Robert" "Bob") ("Theodore" "Ted")) "List of nicknames which are not prefixes of the full name. It is by no means comprehensive.") (defun edb-t-human-names:same-first-name-p (n1 n2) (or (edb-t-human-names:nicknamep n1 n2) (edb-t-human-names:nicknamep n2 n1))) (defun edb-t-human-names:order-first-names (n1 n2) (let ((m1 (db-string-split-first-word n1)) (m2 (db-string-split-first-word n2))) (cond ((or (edb-t-human-names:same-first-name-p (car m1) (car m2)) (edb-t-human-names:same-first-name-p n1 n2)) 0) ((string-lessp (car m1) (car m2)) -1) (t 1)))) (defun edb-t-human-names:nicknamep (nickname fullname) (or (string-match (concat "^" (regexp-quote nickname)) fullname) (member nickname (cdr (assoc (car (db-string-split-first-word fullname)) edb-t-human-names:nicknames))))) ;; ;; Full names ;; (defun edb-t-human-names:standardize-name (name) ;; remove leading honorifics (when (string-match (concat "^\\(\\(Dr\\|Mrs?\\|Prof\\|1?Lt\\)\\.?" "\\|Miss\\|Ensign\\|Doctor\\) ") name) (setq name (substring name (match-end 0)))) ;; remove trailing gubbish (setq name (substring name 0 (string-match ",? \\(PhD\\|MD\\|Esq\\.?\\|Esquire\\)$" name))) ;; add periods after initials (while (string-match "\\(^\\| \\)[A-Z]\\([ ,]\\|$\\)" name) (setq name (concat (substring name 0 (match-beginning 2)) "." (substring name (match-beginning 2))))) name) (defvar edb-t-human-names:jr-assoc-list ; preferred suffixes '(("3d" . "3rd"))) (defun edb-t-human-names:name->name-jr (name) ;; Return (suffixless-name suffix). (if (string-match ",? +\\(jr\\.?\\|sr\\.?\\|3r?d\\|[45]th\\|I+\\)$" name) (list (substring name 0 (match-beginning 0)) (let ((jr (substring name (match-beginning 1)))) (or (cdr (assoc (downcase jr) edb-t-human-names:jr-assoc-list)) jr))) (list name ""))) (defun edb-t-human-names:name->first-last-jr (fullname) ;; Return (fname lname jr). (let* ((jr (edb-t-human-names:name->name-jr (edb-t-human-names:standardize-name fullname))) (ls (db-string-split-last-word (car jr) "\\(La\\|de\\) [A-Z-]+"))) (append ls (cdr jr)))) (provide 'edb-t-human-names) ;;; edb-t-human-names.el ends here edb-1.31/lisp/edb-t-places-usuk.el0000444000175000017500000000725610745616666015133 0ustar ttnttn;;; edb-t-places-usuk.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Places in the US/UK ;; ;; These variables and functions used to be in db-types.el, ;; without the "edb-t-places-usuk:" prefix. ;;; Code: (defvar edb-t-places-usuk:UK-postal-code-regexp "[A-Z][0-9][A-Z] ?[0-9][A-Z][0-9]") (defvar edb-t-places-usuk:zip-code-regexp "[0-9][0-9][0-9][0-9][0-9]\\(-?[0-9][0-9][0-9][0-9]\\)?") (defvar edb-t-places-usuk:postal-code-regexp (mapconcat 'identity (list ;; US zip code edb-t-places-usuk:zip-code-regexp ;; UK postal code edb-t-places-usuk:UK-postal-code-regexp ;; other "[0-9][0-9A-Z]*") "\\|")) (defsubst edb-t-places-usuk:postal-code-p (s) (string-match edb-t-places-usuk:postal-code-regexp s)) ;; Full state-alist and associated functions added by ;; Alan Stebbens, UCSB, Sep 18 '92. (defvar edb-t-places-usuk:state-alist '(("AK" . "Alaska") ("AL" . "Alabama") ("AR" . "Arkansas") ("AZ" . "Arizona") ("CA" . "California") ("CO" . "Colorado") ("CT" . "Conneticut") ("DC" . "District of Columbia") ("DE" . "Deleware") ("FL" . "Florida") ("GA" . "Georgia") ("GU" . "Guam") ("HI" . "Hawaii") ("ID" . "Idaho") ("IL" . "Illinois") ("IN" . "Indiana") ("IA" . "Iowa") ("KS" . "Kansas") ("KY" . "Kentucky") ("LA" . "Louisiana") ("MA" . "Massachusetts") ("MD" . "Maryland") ("ME" . "Maine") ("MI" . "Michigan") ("MN" . "Minnessota") ("MS" . "Mississippi") ("MO" . "Missouri") ("MT" . "Montana") ("NE" . "Nebraska") ("NH" . "New Hampshire") ("NC" . "North Carolina") ("ND" . "North Dakota") ("NJ" . "New Jersey") ("NM" . "New Mexico") ("NV" . "Nevada") ("NY" . "New York") ("OH" . "Ohio") ("OK" . "Oklahoma") ("OR" . "Oregon") ("PA" . "Pennsylvania") ("PR" . "Puerto Rico") ("RI" . "Rhode Island") ("SC" . "South Carolina") ("SD" . "South Dakota") ("TX" . "Texas") ("TN" . "Tennessee") ("UT" . "Utah") ("VA" . "Virginia") ("VT" . "Vermont") ("WA" . "Washington") ("WI" . "Wisconson") ("WV" . "West Virginia") ("WY" . "Wyoming")) "An alist of ABBREV and FULLNAME of each of the United States, and its territories. Used by \"edb-t-places-usuk:full-state-name\" and \"edb-t-places-usuk:abbreviate-state\".") (defun edb-t-places-usuk:statep (obj) "Return non-nil if OBJ is a valid state abbreviation." (when (stringp obj) (edb-t-places-usuk:full-state-name obj))) (defun edb-t-places-usuk:full-state-name (abbrev) "Return the full state name for ABBREV, or nil if not found." (and (= 2 (length abbrev)) (cdr (assoc (upcase abbrev) edb-t-places-usuk:state-alist)))) (defun edb-t-places-usuk:abbreviate-state (state) "Return the postal abbreviation for STATE, or nil if not found." (car (rassoc (capitalize state) edb-t-places-usuk:state-alist))) (provide 'edb-t-places-usuk) ;;; edb-t-places-usuk.el ends here edb-1.31/lisp/edb-t-timedate1.el0000444000175000017500000011374010745616666014550 0ustar ttnttn;;; edb-t-timedate1.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Library of date and time types for EDB database fields. ;; This file is an extension of db-types.el. ;; ;; This file defines the date and time record types, plus several kinds of ;; date- and time-related display types, with variations on formatting. ;; ;; For efficiency, the types are defined in terms of the displayspec ;; abstraction instead of via format strings. ;; ;; These variables and functions used to be in db-time.el, ;; without the "edb-t-timedate1:" prefix. The "1" is because ;; db-time.el originated with EDB 1.x (or perhaps even earlier). ;; Since then, Emacs has incorporated time/date functionality ;; that is incompatible w/ this interface. ;; ;; Performance note: ;; If the speed of reading and writing database files is very important to ;; you, consider using `fset' to set `edb-t-timedate1:date->storage-string' ;; `edb-t-timedate1:storage-string->date' to more efficient functions, ;; such as `edb-t-timedate1:date->storage-string-mmddyyyy' and ;; `edb-t-timedate1:storage-string-mmddyyyy->date', or ;; `edb-t-timedate1:date->storage-string-lisp' ;; and `edb-t-timedate1:storage-string-lisp->date'. ;;; Code: (require 'edbcore) (eval-when-compile (require 'cl)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Dates ;;; ;;; ;;; Abstraction: dotted list of (year month . day), all integers. ;;; (defsubst edb-t-timedate1:make-date (year month day) "Make an EDB 1.x date object from YEAR, MONTH and DAY." (cons year (cons month day))) (defsubst edb-t-timedate1:date-year (date) (car date)) (defsubst edb-t-timedate1:date-month (date) (car (cdr date))) (defsubst edb-t-timedate1:date-day (date) (cdr (cdr date))) (defsubst edb-t-timedate1:make-empty-date () "Return an EDB 1.x date object containing no information." (edb-t-timedate1:make-date nil nil nil)) (defun edb-t-timedate1:date-year-long (date) "Extract the year from an EDB 1.x DATE object as a four digit value." (let ((yy (edb-t-timedate1:date-year date))) (cond ((< yy 50) (+ 2000 yy)) ((< yy 99) (+ 1900 yy)) (t yy)))) ;;; Years (defun edb-t-timedate1:date->day-of-year (date) "Return the day number within the year for Gregorian DATE." ;; ;; An explanation of the calculation can be found in PascAlgorithms by ;; Edward and Ruth Reingold, Scott-Foresman/Little, Brown, 1988. ;; (let* ((month (edb-t-timedate1:date-month date)) (day (edb-t-timedate1:date-day date)) (year (edb-t-timedate1:date-year date)) (day-of-year (+ day (* 31 (1- month))))) (if (> month 2) (progn (decf day-of-year (/ (+ 23 (* 4 month)) 10)) (if (or (and (= (% year 4) 0) (/= (% year 100) 0)) (= (% year 400) 0)) (incf day-of-year)))) day-of-year)) (defun edb-t-timedate1:date->absolute-days (date) "Return the number of days elapsed between the Gregorian 12/31/1 BC and DATE. The Gregorian date Sunday, December 31, 1 BC is imaginary." (let ((mm (edb-t-timedate1:date-month date)) (dd (edb-t-timedate1:date-day date)) (yy (1- (edb-t-timedate1:date-year-long date)))) (+ (edb-t-timedate1:date->day-of-year date) ; + days in this year (* 365 yy) ; + days in prior years (/ yy 4) ; + Julian leap years (- (/ yy 100)) ; - century years (/ yy 400)))) ; + Gregorian leap years ;;; Weekdays (defsubst edb-t-timedate1:date->weekday-index (date) "Return the weekday index for DATE." (% (edb-t-timedate1:date->absolute-days date) 7)) (defsubst edb-t-timedate1:date->weekday-name (date) "Return the weekday name for the DATE." (aref ;; Sunday must come first -- absolute dates begin on Sunday, Dec 31, 1BC. ["Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday"] (edb-t-timedate1:date->weekday-index date))) ;;; Months ;; These sub-alists aren't really necessary; they're only used to make the ;; associated arrays. And the full alist is used, of course. But it uses ;; different cons cells, which is a waste. (defconst edb-t-timedate1:full-monthname-alist '(("January" . 1) ("February" . 2) ("March" . 3) ("April" . 4) ("May" . 5) ("June" . 6) ("July" . 7) ("August" . 8) ("September" . 9) ("October" . 10) ("November" . 11) ("December" . 12))) (defconst edb-t-timedate1:monthabbrev-alist '(("Jan" . 1) ("Feb" . 2) ("Mar" . 3) ("Apr" . 4) ("May" . 5) ("Jun" . 6) ("Jul" . 7) ("Aug" . 8) ("Sep" . 9) ("Oct" . 10) ("Nov" . 11) ("Dec" . 12))) (defconst edb-t-timedate1:monthname-alist (append edb-t-timedate1:monthabbrev-alist edb-t-timedate1:full-monthname-alist '(("Sept" . 9)))) ;; Why do I need this in an array? (Why not?) (Well, it's extra space.) (defconst edb-t-timedate1:monthabbrev-array (vconcat '("") (mapcar 'car edb-t-timedate1:monthabbrev-alist))) (defconst edb-t-timedate1:monthname-array (vconcat '("") (mapcar 'car edb-t-timedate1:full-monthname-alist))) ;;; Ordering (defun edb-t-timedate1:date-order-absolute (d1 d2) (let ((rv (db-number-or-nil-order-nil-greatest (edb-t-timedate1:date-year d1) (edb-t-timedate1:date-year d2)))) (when (zerop rv) (setq rv (db-number-or-nil-order-nil-greatest (edb-t-timedate1:date-month d1) (edb-t-timedate1:date-month d2)))) (when (zerop rv) (setq rv (db-number-or-nil-order-nil-greatest (edb-t-timedate1:date-day d1) (edb-t-timedate1:date-day d2)))) rv)) ;;; ;;; Regexps ;;; (defconst edb-t-timedate1:date-regexps (let* ((monthname (concat "\\(" (mapconcat 'car edb-t-timedate1:monthname-alist "\\|") "\\)\\.?")) (weekday (concat "\\(" (mapconcat 'identity '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Tues" "Thurs" "Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") "\\|") "\\)\\.?")) (monthno "\\(0?[1-9]\\|1[0-2]\\)") (monthno-two-char "\\(0[1-9]\\|1[0-2]\\)") (monthday "\\(0?[1-9]\\|[12][0-9]\\|3[01]\\)") (monthday-two-char "\\([0-2][0-9]\\|3[01]\\)") ;; NOTE: No surrounding ()! (full-year "[0-2][0-9][0-9][0-9]") (short-year "[0-9][0-9]") ;; NOTE: No internal grouping; is that intentional? That is, this ;; only counts as one grouping when counting regexp matches, because ;; I didn't use any internal \\( \\). (year (concat "\\(" full-year "\\|" short-year "\\)")) (sep "[ -.,/']+")) (list ;; MMDDYY (cons (concat monthname sep monthday "\\(" sep year "\\)?") '(4 nil 1 2)) (cons (concat monthno sep monthday "\\(" sep year "\\)?") '(4 1 nil 2)) ;; DDMMYY (cons (concat monthday sep monthname "\\(" sep year "\\)?") '(4 nil 2 1)) (cons (concat "\\(" monthday sep "\\)?" monthname sep year) '(4 nil 3 2)) (cons (concat monthday sep monthno sep "\\(" full-year "\\)") '(3 2 nil 1)) ;; YYMMDD ;; Using year instead of full-year is ambiguous (consider ;; 11-11-11), but we already tried MMDDYY and it failed. (cons (concat year sep monthname sep monthday) '(1 nil 2 3)) (cons (concat year sep monthno sep monthday) '(1 2 nil 3)) ;; YYMMDD, no separators ;; This is ambiguous. (cons (concat year monthno-two-char "?" monthday-two-char "?") '(1 2 nil 3)) ;; WWMMDDYY (cons (concat weekday sep monthname sep monthday "\\(" sep year "\\)?") '(5 nil 2 3)) ;; WWDDMMYY (cons (concat weekday sep monthday sep monthname "\\(" sep year "\\)?") '(5 nil 3 2)) ;; ctime (cons (concat weekday " " monthname " ?" monthday ;; time of day " [0-9:]+ " "\\(" full-year "\\)") '(4 nil 2 3)))) "Assoc list of regexps and match locators. A match locator is a list of four numbers indicating which submatch of the regexp contains the year, month number, month name, and day of the month. The list elements may be nil if that information is not available.") ;;; ;;; Parsing dates ;;; (defun edb-t-timedate1:parse-date-string (s) "Parse string S, and return an EDB 1.x date object. Signal error if the parse is invalid. If S contains only whitespace, return a null date object. If S is nil, use the result of calling `edb-t-timedate1:parse-date-default-function' instead." (let ((rxls edb-t-timedate1:date-regexps) (son->non (lambda (s-o-n) (when s-o-n (db-string->number-or-nil s-o-n)))) rv mls) (setq s (if (null s) ; provide default date for nil strings (edb-t-timedate1:parse-date-default-function) (db-string-trim-whitespace s))) (if (zerop (length s)) ; if empty string, (edb-t-timedate1:make-empty-date) ; return empty date ;; rxls is nulled if a match is found (while rxls (if (string-match (concat "^" (car (car rxls)) "$") s) ;; Bug in version 18 save-match-data: it's impossible ;; to have a marker at 0, so this gets converted to 1. (setq mls (mapcar (lambda (m) (when m (match-string m s))) (cdr (car rxls))) ;; mls is year, monthnumber, monthname, day rv (edb-t-timedate1:make-date (funcall son->non (car mls)) (or (funcall son->non (car (cdr mls))) (and (car (cdr (cdr mls))) ;; match is non-nil; don't check match-beginning ;; At one time this clobbered the match-data. (cdr (assoc (capitalize (car (cdr (cdr mls)))) edb-t-timedate1:monthname-alist)))) (funcall son->non (nth 3 mls))) rxls nil) ;; string-match failed (setq rxls (cdr rxls)))) (if rv (if (if (edb-t-timedate1:date-day rv) (if (edb-t-timedate1:date-month rv) (<= (edb-t-timedate1:date-day rv) (aref [0 31 28 31 30 31 30 31 31 30 31 30 31] (edb-t-timedate1:date-month rv))) (error "Date has a day but no month")) t) (if (and (let ((y (edb-t-timedate1:date-year rv))) (or (not y) (zerop y))) (let ((m (edb-t-timedate1:date-month rv))) (or (not m) (zerop m))) (let ((d (edb-t-timedate1:date-day rv))) (or (not d) (zerop d)))) (edb-t-timedate1:make-empty-date) rv) (error "There is no such day as %s %d!" (aref edb-t-timedate1:monthname-array (edb-t-timedate1:date-month rv)) (edb-t-timedate1:date-day rv))) (error "`%s' is not a valid date." s))))) (defun edb-t-timedate1:parse-date-string-or-nil (s) "Like `edb-t-timedate1:parse-date-string', but return null date in case arg S is nil." (if s (edb-t-timedate1:parse-date-string s) (edb-t-timedate1:make-empty-date))) (defvar edb-t-timedate1:parse-date-default 'empty "A symbol: `empty' or 'current-date', specifying what date string `edb-t-timedate1:parse-date-default-function' should return, and `edb-t-timedate1:parse-date-string' should use when passed a nil argument.") (defun edb-t-timedate1:parse-date-default-function () "Return a default value for `edb-t-timedate1:parse-date-string' to use if its input is nil." (case edb-t-timedate1:parse-date-default ((empty) "") ((today current-date current-time current-time-string) (current-time-string)) (t (error "Bad `edb-t-timedate1:parse-date-default' value: %S" edb-t-timedate1:parse-date-default)))) ;; AKS, UCSB, 9/30/92 ;; ;; General purpose date format routine ;; *WARNING*: If any new escape symbols are added, BE SURE that they are ;; placed in order of longest symbol first, so that the regexp computed ;; below works properly. (defconst edb-t-timedate1:format-date-sub-syms-alist (eval-when-compile (let* ((Y '(edb-t-timedate1:date-year date)) (M '(edb-t-timedate1:date-month date)) (D '(edb-t-timedate1:date-day date)) (raw (list ;; days "day" D '(substring (edb-t-timedate1:date->weekday-name date) 0 3) "dd" D `(format "%02d" ,D) "d" D D ;; months "month" M `(aref edb-t-timedate1:monthname-array ,M) "mon" M `(aref edb-t-timedate1:monthabbrev-array ,M) "mm" M `(format "%02d" ,M) "m" M M ;; years "year" Y '(edb-t-timedate1:date-year-long date) "yy" Y `(format "%02d" (% ,Y 100)) ;; misc "jday" `(and ,D ,M ,Y) '(edb-t-timedate1:date->day-of-year date) "wday" `(and ,D ,M ,Y) '(edb-t-timedate1:date->weekday-index date) "weekday" `(and ,D ,M ,Y) '(edb-t-timedate1:date->weekday-name date))) alist) (while raw (let ((name (pop raw)) (test (pop raw)) (doit (pop raw))) (push `(,name . ((lambda (date) ,test) . (lambda (date) ,doit))) alist))) (nreverse alist))) "An alist of (NAME . (TEST . DOIT)) used by `edb-t-timedate1:format-date'. Each NAME is a string, which, when prefixed by \"%\", will be substituted by the value of calling the associated DOIT but only if calling TEST returns non-nil. Calling is done with one arg, the date object.") ;; Build a regexp which matches the symbol names given above (defconst edb-t-timedate1:format-date-sub-syms-regexp (concat "%\\(" (mapconcat 'car edb-t-timedate1:format-date-sub-syms-alist "\\|") "\\)") "A regexp pattern to parse format strings for symbol substition strings; computed from the variable `edb-t-timedate1:format-date-sub-syms-alist'.") (defun edb-t-timedate1:format-date (fmtstr &optional date) "Using FMTSTR, format the DATE, which defaults to the current date if nil. FMTSTR can contain the following symbol strings, which are substituted by their corresponding value from the date; other characters are inserted as-is. String Action ====== ====== %d day of month -- 1 to 31 (one or two digits) %dd day of month -- 01 to 31 (always two digits) %m month of year - 1 to 12 (one or two digits) %mm month of year - 01 to 12 (always two digits) %mon month name (abbreviated) - Jun %month full month name - June %yy last 2 digits of year - 00 to 99 %year year as 4 digits -- 0000 to 9999? %jday Julian day of year -- 1 to 366 %wday day of week -- 0 to 6 (Sunday = 0) %day day of week name -- \"Sun\" to \"Sat\" %weekday full day of week name -- \"Sunday\" to \"Saturday\" See the variables `edb-t-timedate1:format-date-sub-syms-alist' and `edb-t-timedate1:format-date-sub-syms-regexp'. A special case: if an element of DATE is nil, its field is hidden. A DATE object of all nils is thus formatted as the empty string." (when (null date) (setq date (edb-t-timedate1:parse-date-string nil))) (let* ((ofs 0) (buf "") sym-alist x) (while (setq x (string-match edb-t-timedate1:format-date-sub-syms-regexp fmtstr ofs)) (if (not (setq sym-alist (assoc (match-string 1 fmtstr) edb-t-timedate1:format-date-sub-syms-alist))) (error "Not in `edb-t-timedate1:format-date-sub-syms-alist': %s" (match-string 1 fmtstr)) ;; Does TEST work? (when (funcall (car (cdr sym-alist)) date) ;; Yes; insert its prefix string and its value. (setq buf (format "%s%s%s" buf (if (string= buf "") buf (substring fmtstr ofs x)) (funcall (cdr (cdr sym-alist)) date))))) ;; Skip past the variable. (setq ofs (match-end 0))) (concat buf (substring fmtstr ofs)))) (defconst edb-t-timedate1:simple-format-date-default "%month %d, %year" "*A default format used by edb-t-timedate1:simple-format-date.") ;; Note only one argument (defun edb-t-timedate1:simple-format-date (date) "Format the DATE using a default format, defined by the variable `edb-t-timedate1:simple-format-date-default'. If DATE is nil, use the value of `edb-t-timedate1:parse-date-default-function'." (edb-t-timedate1:format-date edb-t-timedate1:simple-format-date-default date)) (defun edb-t-timedate1:simple-format-date-or-nil (date) "Format the DATE using a default format, defined by the variable `edb-t-timedate1:simple-format-date-default'. If DATE is nil, return the empty string." (if date (edb-t-timedate1:format-date edb-t-timedate1:simple-format-date-default date) "")) ;; AKS, edb-t-timedate1:format-date-xxx routines ;; The following display functions are used below ;; in the displayspec definitions: ;; ;; Function Sample Default ;; ==================================== ========== ======= ;; edb-t-timedate1:format-date-mmddyy 06/10/54 "/" ;; edb-t-timedate1:format-date-yymmdd 540610 "" ;; edb-t-timedate1:format-date-ddmmyy 10.06.54 "." ;; edb-t-timedate1:format-date-ddmmmyy 10 Jun 54 " " ;; edb-t-timedate1:format-date-yyyymmdd 1954/06/10 "/" ;; ;; -europe 10.06.54 ;; -dec 10-Jun-54 ;; -full June 10, 1954 ;; -unix Sun Jun 10 1954 ;; -all Sunday, June 10, 1954 (defun edb-t-timedate1:format-date-mmddyy (date &optional separator) "Format the DATE into a \"%mm/%dd/%yy\" format. Optional arg SEPARATOR is a string to use instead of \"/\". If DATE is nil, return the empty string." (if date (let ((sep (or separator "/"))) (edb-t-timedate1:format-date (format "%%mm%s%%dd%s%%yy" sep sep) date)) "")) (defun edb-t-timedate1:format-date-ddmmyy (date &optional separator) "Format the DATE into a \"%dd.%mm.%yy\" format. Optional arg SEPARATOR a string to use instead of \".\". If DATE is nil, return the empty string." (if date (let ((sep (or separator "."))) (edb-t-timedate1:format-date (format "%%dd%s%%mm%s%%yy" sep sep) date)) "")) (defun edb-t-timedate1:format-date-yymmdd (date &optional separator) "Format the DATE into a \"%yy%mm%dd\" format. Optional arg SEPARATOR is a string to use instead of \"\" (empty string). If DATE is nil, return the empty string." (if date (let ((sep (or separator ""))) (edb-t-timedate1:format-date (format "%%yy%s%%mm%s%%dd" sep sep) date)) "")) (defun edb-t-timedate1:format-date-ddmmmyy (date &optional separator) "Format the DATE into a \"%dd %mon %yy\" format. Optional arg SEPARATOR is a string to use instead of \" \" (space). If DATE is nil, return the empty string." (if date (let ((sep (or separator " "))) (edb-t-timedate1:format-date (format "%%dd%s%%mon%s%%yy" sep sep) date)) "")) (defun edb-t-timedate1:format-date-yyyymmdd (date &optional separator) "Format the DATE into a \"%year/%mm/%dd\" format. Optional arg SEPARATOR is a string to use instead of \"/\". If DATE is nil, return the empty string." (if date (let ((sep (or separator "/"))) (edb-t-timedate1:format-date (format "%%year%s%%mm%s%%dd" sep sep) date)) "")) (defun edb-t-timedate1:format-date-full (date) "Format the DATE into the full format: %month %d, %year. If DATE is nil, return the empty string." (if date (edb-t-timedate1:format-date "%month %d, %year" date) "")) (defun edb-t-timedate1:format-date-unix (date) "Format the DATE into the standard Unix format: %day %mon %d %year. If DATE is nil, return the empty string." (if date (edb-t-timedate1:format-date "%day %mon %d %year" date) "")) (defun edb-t-timedate1:format-date-all (date) "Format the DATE using all components, without abbreviations, in the format: %weekday, %month %d, %year. If DATE is nil, return the empty string." (if date (edb-t-timedate1:format-date "%weekday, %month %d, %year" date) "")) ;; Some common variations on a theme (defun edb-t-timedate1:format-date-dec (date) "Format the DATE into the standard DEC format: dd-mmm-yy. If DATE is nil, return the empty string." (edb-t-timedate1:format-date-ddmmmyy date "-")) (defun edb-t-timedate1:format-date-europe (date) "Format the DATE into the European standard, which is DD.MM.YY. If DATE is nil, return the empty string." (edb-t-timedate1:format-date-ddmmyy date ".")) (defun edb-t-timedate1:format-date-iso (date) "Format the DATE into a \"%year-%mm-%dd\" format. If DATE is nil, return the empty string." (edb-t-timedate1:format-date-yyyymmdd date "-")) ;;; ;;; EDB type definitions ;;; (edb-define-displaytype 'date nil :indent nil :actual->display 'edb-t-timedate1:simple-format-date :display->actual 'edb-t-timedate1:parse-date-string) (edb-define-recordfieldtype 'date nil :type 'date :default-value (edb-t-timedate1:make-empty-date) :actual->stored 'edb-t-timedate1:date->storage-string :stored->actual 'edb-t-timedate1:storage-string->date :merge-function 'edb-t-timedate1:date-merge :order-fn 'edb-t-timedate1:date-order-absolute :match-function 'edb-t-timedate1:date-match-function :help-info "A date.") (edb-define-recordfieldtype 'date-efficient-storage 'date :stored->actual 'edb-t-timedate1:storage-string->date) (edb-define-displaytype 'date-or-nil 'date :actual->display 'edb-t-timedate1:simple-format-date-or-nil :display->actual 'edb-t-timedate1:parse-date-string-or-nil) (edb-define-recordfieldtype 'date-or-nil 'date :type 'date-or-nil :default-value nil :stored->actual 'edb-t-timedate1:parse-date-string-or-nil :help-info "(Optional) date.") (dolist (type '("mmddyy" "yymmdd" "ddmmyy" "ddmmmyy" "yyyymmdd" "iso" "europe" "full" "all" "unix" "dec")) ; RIP (snif) --ttn (edb-define-displaytype (intern (concat "date-" type)) 'date :actual->display (intern (concat "edb-t-timedate1:format-date-" type)))) (defun edb-t-timedate1:date-match-function (pat targ) (and (or (not (edb-t-timedate1:date-year pat)) (and (edb-t-timedate1:date-year targ) (= (edb-t-timedate1:date-year pat) (edb-t-timedate1:date-year targ)))) (or (not (edb-t-timedate1:date-month pat)) (and (edb-t-timedate1:date-month targ) (= (edb-t-timedate1:date-month pat) (edb-t-timedate1:date-month targ)))) (or (not (edb-t-timedate1:date-day pat)) (and (edb-t-timedate1:date-day targ) (= (edb-t-timedate1:date-day pat) (edb-t-timedate1:date-day targ)))))) (defun edb-t-timedate1:date-merge (d1 d2) ;; If an item of a date is nil, use the other date's value. (let ((mm (or (edb-t-timedate1:date-month d1) (edb-t-timedate1:date-month d2))) (dd (or (edb-t-timedate1:date-day d1) (edb-t-timedate1:date-day d2))) (yy (or (edb-t-timedate1:date-year d1) (edb-t-timedate1:date-year d2)))) (edb-t-timedate1:make-date yy mm dd))) ;; File representation (fset 'edb-t-timedate1:date->storage-string 'edb-t-timedate1:format-date-full) (fset 'edb-t-timedate1:storage-string->date 'edb-t-timedate1:date-stored->actual) (defun edb-t-timedate1:date->storage-string-mmddyyyy (date) ;; This is fairly human-readable, but ambiguous. (if (edb-t-timedate1:date-year date) (format "%02d/%02d/%02d" (or (edb-t-timedate1:date-month date) 0) (or (edb-t-timedate1:date-day date) 0) (or (edb-t-timedate1:date-year date) 0)) (if (not (or (edb-t-timedate1:date-month date) (edb-t-timedate1:date-day date))) "" (format "%02d/%02d" (or (edb-t-timedate1:date-month date) 0) (or (edb-t-timedate1:date-day date) 0))))) (defun edb-t-timedate1:storage-string-mmddyyyy->date (s) (let ((mm (db-string->integer (substring s 0 2))) (dd (db-string->integer (substring s 3 5))) (yyyy (and (> (length s) 5) (db-string->integer (substring s 6))))) (edb-t-timedate1:make-date (if (not (zerop mm)) mm) (if (not (zerop dd)) dd) (if (and yyyy (not (zerop yyyy))) yyyy)))) (defun edb-t-timedate1:date->storage-string-lisp (date) ;; This is quite fast, but not very human-readable. (format "%s" date)) (defun edb-t-timedate1:storage-string-lisp->date (s) (car (read-from-string s))) (defun edb-t-timedate1:date-stored->actual (s) ;; Don't do anything if S is already a date. The point is to DTRT even when ;; the field didn't appear in the database file, so the record field got set ;; to the empty date rather than the empty string. (if (stringp s) ;; This is slow but general. (edb-t-timedate1:parse-date-string s) s)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Times ;;; ;;; Much of this was lifted from Dates ;;; Otherwise it was written by Alan K. Stebbens, UCSB ;;; ;;; Display types: time, time-12, time-24, time-12-hhmm, time-24-hhmm, ;;; and time-hhmm. ;;; Field Types: time, time-12, time-24, and time-arb-storage ;;; Functions: (all prefixed w/ "edb-t-timedate1:") ;;; parse-time-string, format-time-12, format-time-24 ;;; time->storage-string, storage-string->time, ;;; time-order, time-merge, time-match-function, ;;; db-time-default-constraint ;;; ;;; Abstraction: TIME object is a 3-elt list (this allows `nth' to work) (defsubst edb-t-timedate1:make-time (hours mins secs) "Return a new EDB 1.x time object made from HOURS, MINS and SECS." (list hours mins secs)) (defsubst edb-t-timedate1:time-hours (time) (car time)) (defsubst edb-t-timedate1:time-mins (time) (car (cdr time))) (defsubst edb-t-timedate1:time-secs (time) (car (cdr (cdr time)))) (defsubst edb-t-timedate1:make-empty-time () "Return a new EDB 1.x time object containing no information." (edb-t-timedate1:make-time nil nil nil)) (defun edb-t-timedate1:empty-time-p (time) "Return t if all the TIME object's slots contain nil, nil otherwise." (and (null (edb-t-timedate1:time-hours time)) (null (edb-t-timedate1:time-mins time)) (null (edb-t-timedate1:time-secs time)))) (defun edb-t-timedate1:time-default-constraint (time rec idx db) "Enforce proper EDB 1.x time object values." (if (or (edb-t-timedate1:empty-time-p time) (and (< (edb-t-timedate1:time-hours time) 23) (< (edb-t-timedate1:time-mins time) 59) (< (edb-t-timedate1:time-secs time) 59))) t (error "Invalid time value."))) ;; edb-t-timedate1:parse-time-string ;; ;; State-driven time parser; I converted this from my Perl time parser. ;; Alan K. Stebbens, UCSB (defconst edb-t-timedate1:parse-time-regexp-array [ "\\([0-9]?[0-9]\\)\\(:\\| ?[ap]m\\)" "\\([0-5][0-9]\\)\\(:\\| ?[ap]m\\|\\Sw\\|$\\)" "\\([0-5][0-9]\\)\\( *[ap]m\\|\\Sw\\|$\\)" ] "An array of regexps used by edb-t-timedate1:parse-time-string, indexed by the current parse state to obtain the appropriate regexp.") (defun edb-t-timedate1:parse-time-string (s) "Parse the first occurrence of hh:mm:ss in string S; return a time object. If \":ss\" is hidden in S, the seconds default to zero. If S contains only whitespace, return an empty time object. If S is nil, use instead the result of `edb-t-timedate1:parse-time-default-function'." (setq s (if (not s) ; provide default time for nil strings (edb-t-timedate1:parse-time-default-function) (db-string-trim-whitespace s))) (if (zerop (length s)) (edb-t-timedate1:make-empty-time) (let ((case-fold-search t) ;; Initial regexp matches HH: or HHpm (hh 0) (mm 0) (ss 0) pm (vars '[hh mm ss]) (ofs 0) (state 0)) (while (and (< state 3) (< ofs (length s)) (string-match (aref edb-t-timedate1:parse-time-regexp-array state) s ofs)) (set (aref vars state) (string-to-number (match-string 1 s))) (setq state (if (equal ":" (match-string 2 s)) (1+ state) 3)) (setq ofs (match-end 0))) (edb-t-timedate1:make-time (if (and (setq pm (match-string 2 s)) (string-match "[ap]m" pm)) (+ (% hh 12) (if (string-match "pm" pm) 12 0)) hh) mm ss)))) (defvar edb-t-timedate1:parse-time-default 'empty "One of the symbols `empty' or `current-time' or `now' (these last two are equivalent), specifying what `edb-t-timedate1:parse-time-default-function' should return, and `edb-t-timedate1:parse-time-string' should use when passed a nil argument.") (defun edb-t-timedate1:parse-time-default-function () "Return a default value for `edb-t-timedate1:parse-time-string' to use if its input is nil." (case edb-t-timedate1:parse-time-default ((empty) "") ((current-time now) (current-time-string)) (t (error "Unrecognized value `%s' for variable `%s'" edb-t-timedate1:parse-time-default 'edb-t-timedate1:parse-time-default)))) ;; test routine for above '(defun test-time-parser () (interactive) (dolist (time '("1am" "1pm" "1 pm" "1 PM" "1:01am" "1:02pm" "12:01:01am" "12:01:01pm" "12:34:45" " 12:34:45" " 12:34:45 " "12:34:45 " "May 12 14:34 1992" "May 19 10:17:23pm 1992" "May 19 10:17:23 pm 1992")) (message "In = \"%s\" Out = \"%s\" (CR for next)" time (edb-t-timedate1:parse-time-string time)) (read-char))) (defun edb-t-timedate1:format-time-24 (time) "Format TIME (a three element list) into a 24 hour time string in the format HH:MM:SS. If an element of the list is nil, that component is not edited. Typically, the seconds element is hidden or set to nil to produce a time format with only HH:MM. See `edb-t-timedate1:format-time-24-hhmm'." (let ((hh (edb-t-timedate1:time-hours time)) (mm (edb-t-timedate1:time-mins time)) (ss (edb-t-timedate1:time-secs time))) (concat (and hh (format "%d" hh)) (and hh mm ":") (and mm (format "%02d" mm)) (and mm ss (format ":%02d" ss))))) (defun edb-t-timedate1:format-time-12 (time) "Format TIME (a 3 element list) into a 12 hour time string in the format HH:MM:SS PM. If an element of the list is nil, that component is not edited. Typically, the seconds element is hidden or set to nil to produce a time format with only HH:MM. See `edb-t-timedate1:format-time-12-hhmm'." (let ((hh (edb-t-timedate1:time-hours time)) (mm (edb-t-timedate1:time-mins time)) (ss (edb-t-timedate1:time-secs time))) (concat (and hh (format "%d" (cond ((zerop hh) 12) ((< hh 13) hh) (t (- hh 12))))) (and hh mm ":") (and mm (format "%02d" mm)) (and mm ss (format ":%02d" ss)) (and hh (if (>= hh 12) "pm" "am"))))) (fset 'edb-t-timedate1:format-time-hhmm 'edb-t-timedate1:format-time-12-hhmm) (defun edb-t-timedate1:format-time-12-hhmm (time) "Format TIME in HH:MM PM format." (edb-t-timedate1:format-time-12 (edb-t-timedate1:make-time (edb-t-timedate1:time-hours time) (edb-t-timedate1:time-mins time) nil))) (defun edb-t-timedate1:format-time-24-hhmm (time) "Format TIME in 24-hour format without seconds." (edb-t-timedate1:format-time-24 (edb-t-timedate1:make-time (edb-t-timedate1:time-hours time) (edb-t-timedate1:time-mins time) nil))) ;;; ;;; EDB type specifications ;;; (edb-define-displaytype 'time nil :indent nil :actual->display 'edb-t-timedate1:format-time-12 :display->actual 'edb-t-timedate1:parse-time-string) (dolist (type '("12" ; am/pm time "24" ; military time "hhmm" ; synonym for time-12-hhmm "12-hhmm" ; am/pm w/o secs "24-hhmm")) ; military w/o secs (edb-define-displaytype (intern (concat "time-" type)) 'time :actual->display (intern (concat "edb-t-timedate1:format-time-" type)))) (edb-define-recordfieldtype 'time nil :type 'time :default-value (edb-t-timedate1:make-empty-time) :constraint-function 'edb-t-timedate1:time-default-constraint :actual->stored 'edb-t-timedate1:time->storage-string :stored->actual 'edb-t-timedate1:storage-string->time :merge-function 'edb-t-timedate1:time-merge :order-fn 'edb-t-timedate1:time-order :match-function 'edb-t-timedate1:time-match-function :help-info "A time.") (edb-define-recordfieldtype 'time-12 'time :help-info "A 12-hour time, with AM/PM.") (edb-define-recordfieldtype 'time-24 'time :help-info "A 24-hour time (a.k.a. military time).") (edb-define-recordfieldtype 'time-arb-storage 'time :stored->actual 'edb-t-timedate1:parse-time-string) (defun edb-t-timedate1:time-order (t1 t2) (let ((result 0) (n 0)) (while (and (<= n 2) (zerop result)) (setq result (db-number-or-nil-order-nil-greatest (nth n t1) (nth n t2)))) result)) (defun edb-t-timedate1:time-match-function (pat targ) (and (or (not (edb-t-timedate1:time-hours pat)) (and (edb-t-timedate1:time-hours targ) (= (edb-t-timedate1:time-hours pat) (edb-t-timedate1:time-hours targ)))) (or (not (edb-t-timedate1:time-mins pat)) (and (edb-t-timedate1:time-mins targ) (= (edb-t-timedate1:time-mins pat) (edb-t-timedate1:time-mins targ)))) (or (not (edb-t-timedate1:time-secs pat)) (and (edb-t-timedate1:time-secs targ) (= (edb-t-timedate1:time-secs pat) (edb-t-timedate1:time-secs targ)))))) (defun edb-t-timedate1:time->storage-string (time) (format "%02d:%02d:%02d" (or (edb-t-timedate1:time-hours time) 0) (or (edb-t-timedate1:time-mins time) 0) (or (edb-t-timedate1:time-secs time) 0))) (defun edb-t-timedate1:storage-string->time (s) (edb-t-timedate1:make-time (db-string->integer (substring s 0 2)) (db-string->integer (substring s 3 5)) (db-string->integer (substring s 6 8)))) (defun edb-t-timedate1:time-merge (t1 t2) ;; If an item in one time is nil, take the other time's value. (let ((hh (or (edb-t-timedate1:time-hours t1) (edb-t-timedate1:time-hours t2))) (mm (or (edb-t-timedate1:time-mins t1) (edb-t-timedate1:time-mins t2))) (ss (or (edb-t-timedate1:time-secs t1) (edb-t-timedate1:time-secs t2)))) (edb-t-timedate1:make-time hh mm ss))) (provide 'edb-t-timedate1) ;;; edb-t-timedate1.el ends here edb-1.31/lisp/state.el0000444000175000017500000000636110745370012013000 0ustar ttnttn;;; state.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;;; Code: (defvar edb--global-state (make-hash-table :test 'eq) "EDB internals.") (defsubst edb--arrrr! (loc) (let ((par edb--global-state)) (while loc (setq par (gethash (car loc) par) loc (cdr loc))) par)) (defun edb--rinit (loc key &rest init) (assert loc) (let ((par (edb--arrrr! loc))) ;; Return the new hash table. (puthash key (apply 'make-hash-table init) par))) (defun edb--rget (loc key) (let ((par (edb--arrrr! loc))) (gethash key par))) (defun edb--rput (loc key value) (let ((par (edb--arrrr! loc))) (puthash key value par))) (defun edb--rforget (loc key) (let* ((par (edb--arrrr! loc)) (v (gethash key par))) (when (hash-table-p v) (clrhash v)) (remhash key par))) :further-init edb--global-state ; (munge this line and suffer, fool!) ;;;--------------------------------------------------------------------------- ;;; Access utilities (defun edb--mputhash (ht &rest init) "Initialize hashtable HT with key1 value1 key2 value2... of INIT." (while init (puthash (pop init) ; DWR: relies on L->R OOE (pop init) ht))) (defun edb--hashcollect (what table) (let (acc) (maphash (case what (:keys (lambda (k v) (setq acc (cons k acc)))) (:vals (lambda (k v) (setq acc (cons v acc)))) (:cons (lambda (k v) (setq acc (acons k v acc))))) table) acc)) (defmacro edb--define-child-hash (get key par init) `(progn (defun ,(intern (format "edb--%s" get)) (,key property) (gethash property (gethash ,key ,par))) (defun ,(intern (format "edb--%s!" get)) (,key property value) (puthash property value (gethash ,key ,par))) (defun ,(intern (format "edb--meta%s" get)) (,key &optional command) (let* ((par ,par) (me (or (gethash ,key par) (puthash ,key ,init par)))) (case command (:forget (clrhash me) (remhash ,key par)) (t me)))))) ;;;--------------------------------------------------------------------------- ;;; Tags (defun edb-tag (name db) "Return the tag object named NAME associated with database DB." (edb--1D db name)) (defun edb-tagp (tag record) "Return t if RECORD has its TAG set." (gethash record tag)) (defun edb-tagx (tag record) "Set TAG for RECORD." (puthash record t tag)) (defun edb-tag- (tag record) "Clear TAG for RECORD." (remhash record tag)) ;;; state.el ends here edb-1.31/lisp/system.el0000444000175000017500000001206710745370012013204 0ustar ttnttn;;; system.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;;; Code: (require 'cl) (require 'easymenu) (unless (fboundp 'with-selected-window) ;; snarfed 2005-01-18 from GNU Emacs subr.el (CVS revision 1.432); ;; modified to call `select-window' with only one arg (defmacro with-selected-window (window &rest body) "Execute the forms in BODY with WINDOW as the selected window. The value returned is the value of the last form in BODY. This does not alter the buffer list ordering. This function saves and restores the selected window, as well as the selected window in each frame. If the previously selected window of some frame is no longer live at the end of BODY, that frame's selected window is left alone. If the selected window is no longer live, then whatever window is selected at the end of BODY remains selected. See also `with-temp-buffer'." (declare (indent 1) (debug t)) ;; Most of this code is a copy of save-selected-window. `(let ((save-selected-window-window (selected-window)) ;; It is necessary to save all of these, because calling ;; select-window changes frame-selected-window for whatever ;; frame that window is in. (save-selected-window-alist (mapcar (lambda (frame) (list frame (frame-selected-window frame))) (frame-list)))) (unwind-protect (progn (select-window ,window) ,@body) (dolist (elt save-selected-window-alist) (and (frame-live-p (car elt)) (window-live-p (cadr elt)) (set-frame-selected-window (car elt) (cadr elt)))) (if (window-live-p save-selected-window-window) (select-window save-selected-window-window)))))) (unless (fboundp 'number-sequence) ;; snarfed 2005-10-27 from GNU Emacs subr.el (CVS revision 1.484) (defun number-sequence (from &optional to inc) "Return a sequence of numbers from FROM to TO (both inclusive) as a list. INC is the increment used between numbers in the sequence and defaults to 1. So, the Nth element of the list is \(+ FROM \(* N INC)) where N counts from zero. TO is only included if there is an N for which TO = FROM + N * INC. If TO is nil or numerically equal to FROM, return \(FROM). If INC is positive and TO is less than FROM, or INC is negative and TO is larger than FROM, return nil. If INC is zero and TO is neither nil nor numerically equal to FROM, signal an error. This function is primarily designed for integer arguments. Nevertheless, FROM, TO and INC can be integer or float. However, floating point arithmetic is inexact. For instance, depending on the machine, it may quite well happen that \(number-sequence 0.4 0.6 0.2) returns the one element list \(0.4), whereas \(number-sequence 0.4 0.8 0.2) returns a list with three elements. Thus, if some of the arguments are floats and one wants to make sure that TO is included, one may have to explicitly write TO as \(+ FROM \(* N INC)) or use a variable whose value was computed with this exact expression. Alternatively, you can, of course, also replace TO with a slightly larger value \(or a slightly more negative value if INC is negative)." (if (or (not to) (= from to)) (list from) (or inc (setq inc 1)) (when (zerop inc) (error "The increment can not be zero")) (let (seq (n 0) (next from)) (if (> inc 0) (while (<= next to) (setq seq (cons next seq) n (1+ n) next (+ from (* n inc)))) (while (>= next to) (setq seq (cons next seq) n (1+ n) next (+ from (* n inc))))) (nreverse seq))))) (unless (fboundp 'help-function-arglist) ;; snarfed 2005-12-07 from GNU Emacs help-fns.el (CVS revision 1.80) (defun help-function-arglist (def) ;; Handle symbols aliased to other symbols. (if (and (symbolp def) (fboundp def)) (setq def (indirect-function def))) ;; If definition is a macro, find the function inside it. (if (eq (car-safe def) 'macro) (setq def (cdr def))) (cond ((byte-code-function-p def) (aref def 0)) ((eq (car-safe def) 'lambda) (nth 1 def)) ((and (eq (car-safe def) 'autoload) (not (eq (nth 4 def) 'keymap))) "[Arg list not available until function definition is loaded.]") (t t)))) ;;; system.el ends here edb-1.31/skram/0000755000175000017500000000000011016452347011504 5ustar ttnttnedb-1.31/skram/GNUmakefile.in0000444000175000017500000000522311016047446014163 0ustar ttnttn# GNUmakefile # Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen # # This file is part of EDB. # # EDB 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 3, or (at your option) any later # version. # # EDB 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 EDB; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. EMACS = @EMACS@ topdir = @abs_top_srcdir@ EXTRABATCHOPTS = --no-site-file --eval '(setq vc-handled-backends nil)' elisp = \ $(patsubst %, $(topdir)/lisp/%.el, system state connection \ edb-1int-to-single) \ $(wildcard $(topdir)/lisp/d*.el) \ $(wildcard $(topdir)/lisp/edb-*.el) all: hacksup.el skram.data sk3 sk4 : note the difference ! diff skram.data sk3 || true ebatch = $(EMACS) -batch $(EXTRABATCHOPTS) hacksup.el: $(elisp) $(ebatch) --load make-hacksup.el $^ skram.data: $(elisp) $(ebatch) --load make-skram.el -f make-skram $^ # Emacs from CVS has a fixed lisp/startup.el that supports the following: #+ wily-emacs = $(ebatch) -L $(topdir) \ #+ --eval '(require (quote database))' # # Until that change is distributed, here is a workaround: wily-emacs = $(ebatch) \ --eval '(add-to-list (quote load-path) (expand-file-name "$(topdir)"))' \ --eval '(require (quote database))' sk2: skram.data $(wily-emacs) \ --eval '(db-find-file "$<")' \ --eval '(db-toggle-internal-file-layout 1)' \ --eval '(setf (database-print-name dbc-database) "SKRAM 2")' \ --eval '(db-write-database-file "$@")' test -L sk2.fmt || ln -s skram.fmt sk2.fmt sk3: sk2 $(wily-emacs) \ --eval '(db-find-file "$<")' \ --eval '(db-toggle-internal-file-layout 0)' \ --eval '(setf (database-print-name dbc-database) "SKRAM 3")' \ --eval '(db-write-database-file "$@")' test -L sk3.fmt || ln -s skram.fmt sk3.fmt sk4: sk2 sed '/"db-oldnames.el"/d;/"db-nosetf.el"/d' $< > $<.TMP $(wily-emacs) \ --eval '(db-find-file "$<.TMP")' \ --eval '(db-toggle-internal-file-layout 1)' \ --eval '(setf (database-print-name dbc-database) "SKRAM 4")' \ --eval '(db-write-database-file "$@")' rm -f $<.TMP test -L sk4.fmt || ln -s skram.fmt sk4.fmt clean: rm -f sk2 sk3 sk4 *~ realclean: clean rm -f skram.data hacksup.el # GNUmakefile ends here edb-1.31/skram/README0000444000175000017500000000005610745370012012357 0ustar ttnttnSelf-Knowledge Requires Attentive Maintenance edb-1.31/skram/make-hacksup.el0000444000175000017500000001010610774216714014401 0ustar ttnttn;;; make-hacksup.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;;; Code: (unless noninteractive (error "See GNUmakefile")) (require 'cl) (fset 'vc-backend (lambda (file) nil)) ; a little too smart sometimes (let ((files (mapcar 'expand-file-name command-line-args-left)) form struct-names explicit indents indents-1) ;; first pass (dolist (file files) (find-file file) (goto-char (point-min)) (while (setq form (ignore-errors (read (current-buffer)))) (unless (consp form) (setq form nil)) (case (car form) (defstruct (let ((conc (cadr form))) (setq conc (if (consp conc) (or (cadr (assq :conc-name (cdr conc))) (format "%s-" (car conc))) (format "%s-" conc))) (push (let ((s (format "%sset-" conc))) (cons s (length s))) struct-names) (dolist (slot (cddr form)) (push (make-symbol (format "%sset-%s" conc (if (consp slot) (car slot) slot))) indents-1)))) (defmacro (let ((name (cadr form)) (maybe-declare (cdddr form))) (setq maybe-declare (if (stringp (car maybe-declare)) (cadr maybe-declare) (car maybe-declare))) (when (and (consp maybe-declare) (eq 'declare (car maybe-declare))) (let ((n (cadr (assq 'indent (cdr maybe-declare))))) (when n (push `(put ',name 'lisp-indent-function ,n) indents)))))) (put (let ((name (cadr form)) (prop (caddr form))) (when (and (consp name) (eq 'quote (car name))) (setq name (cadr name))) (when (and (consp prop) (eq 'quote (car prop))) (setq prop (cadr prop))) (when (memq prop '(lisp-indent-hook lisp-indent-function)) (push form indents) (push name explicit))))))) ;; second pass (dolist (file files) (find-file file) (goto-char (point-min)) (while (setq form (ignore-errors (read (current-buffer)))) (unless (consp form) (setq form nil)) (when (memq (car form) '(defun defsubst)) (let* ((name (cadr form)) (nstr (symbol-name name))) (unless (memq name explicit) (when (some (lambda (pair) (eq t (compare-strings nstr 0 (cdr pair) (car pair) 0 (cdr pair)))) struct-names) (push name indents-1)))))) (kill-buffer nil)) ;; write it out (find-file "hacksup.el") (erase-buffer) (let ((standard-output (current-buffer))) (mapc 'princ '(";;; hacksup.el --- mellifluous munging\n" ";;; (this file is not installed)\n\n" ";; indentation\n")) (pp `(mapc (lambda (func) (put func 'lisp-indent-function 1)) ',indents-1)) (mapc 'pp indents) (princ "\n;;; hacksup.el ends here\n")) (save-buffer) (kill-buffer nil)) ;;; make-hacksup.el ends here edb-1.31/skram/make-skram.el0000444000175000017500000000673010772730711014064 0ustar ttnttn;;; make-skram.el ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;;; Code: (unless noninteractive (error "See GNUmakefile")) (require 'cl) (setq vc-handled-backends nil) ; documented disabling method (defun make-skram () (emacs-lisp-mode) (let ((out (expand-file-name "skram.data")) indexed acc form type name bufs) (dolist (idx '(Function Variable)) (with-temp-buffer ;; The next two forms are equivalent to: ;; (info (format "(edb.info)%s Index" idx) (current-buffer)) ;; but two-arg `info' is not yet (2005-01-18) widely available. (info (format "(%s)%s Index" (expand-file-name "edb.info" "../doc") idx)) (setq buffer-read-only nil) (goto-char (point-min)) (search-forward "* Menu:") (while (re-search-forward "^[*] \\([^: ]+\\)[: ]" (point-max) t) (pushnew (intern (match-string 1)) indexed)))) (dolist (file (mapcar 'expand-file-name command-line-args-left)) (push (find-file file) bufs) (goto-char (point-min)) (while (ignore-errors (setq form (read (current-buffer)))) (setq type (when (consp form) (symbol-name (car form))) name (when type (cadr form))) (when (and type name (not (string-match "^define-" type)) (string-match "^def" type)) (setq name (cond ((atom name) name) ((eq 'quote (car name)) (cadr name)) (t (car name)))) (pushnew (list name (car form) (when (memq name indexed) t) (list (file-name-nondirectory file))) acc :key 'car)))) (dolist (buf bufs) (with-current-buffer buf (let ((file (file-name-nondirectory buffer-file-name)) case-fold-search) (goto-char (point-min)) (dolist (ent acc) (unless (member file (cadddr ent)) (when (and (search-forward (symbol-name (car ent)) (point-max) t) (memq (char-before (match-beginning 0)) '(?( ?) ?' 32))) (push file (cadddr ent)) (goto-char (point-min)))))) (kill-buffer nil))) (erase-buffer) (fundamental-mode) (dolist (ent acc) (insert (format "%s\n:%s\n:%s\n:future unclear\n:" (car ent) (cadr ent) (if (caddr ent) "ok" "maybe"))) (dolist (file (cadddr ent)) (insert file "\n")) (insert "\n")) (let (make-backup-files) (write-file out)) (kill-buffer nil))) ;;; make-skram.el ends here edb-1.31/skram/retired.README0000444000175000017500000000367410745370012014025 0ustar ttnttnThis table lists functions (defmacro, defalias, fset, defun and defsubst), variables (defvar and deflocalvar), and structs that appear in one release but not the next, thus explicitly excluding those elements added and then deleted prior to release (experimental munging). The display format is like so: THING (KIND) DEFAULT-VALUE SINCE --------------------------- COMMENTS --------------------------- DOCUMENTATION All fields are strings. DEFAULT-VALUE and DOCUMENTATION may be empty. SINCE is the first EDB version in which THING no longer appears. COMMENTS is one or more sentences describing the particulars of THING's retirement, perhaps w/ rationale. Common sentences (and their meanings): Unused. Perhaps THING was useful before but it is no longer so. It's also possible that THING was never useful, a heretofore forgotten doodle. Converted to KEYWORD [PLACE]. THING is some kind of variable, or an explicit setter associated w/ a structure slot. The value to be stored is now stored in a hash table (:test 'eq) under key KEYWORD. If PLACE is omitted, the hash table is "local" in some (unspecified) sense, otherwise PLACE is typically "in global hash" or "tag". Note that storage is not reduced. Converted callers to use KEYWORD [PLACE]. Similar to the previous sentence, but the value to be stored is now derived (or derivable) from other sources. Converted callers to use FUNCTION. THING (either a variable or function) is now computed using FUNCTION. Incorporated into [callers | unique caller]. THING is a some kind of function that was inlined into its caller(s). We distinguish the case of a "unique caller" for surveying purposes. Incorporated value as-is. THING is some kind of variable. Dropped ASPECT altogether. THING is part of some ASPECT, which was entirely removed from EDB design or implementation. There are also variations on these common sentences. edb-1.31/skram/retired.data0000444000175000017500000021132210615423746014001 0ustar ttnttn1.28defconstdb-dsym(vector (concat "\\(" (concat "\\\\" db-symbol-regexp) "\\)" (concat "\\(" (aref db-fopt 0) "\\)*") "\\(\\\\ \\)?") 2 1 0 1)Dropped fine-grained regexp-based parsing of displayspecs. 1.28defconstdb-dtrx(concat ",\\(" db-symbol-regexp "\\|" "#\\|\\$\\|\"\\|'\\|\\[[^]]+\\]" "\\)")Dropped fine-grained regexp-based parsing of displayspecs. 1.28defconstdb-fopt(vector (concat db-dtrx "\\(=\\(" "[-<>a-zA-Z0-9]+" "\\)\\)?") 1 3)Dropped fine-grained regexp-based parsing of displayspecs. 1.28defconstdb-symbol-regexp"[a-zA-Z][-<>a-zA-Z0-9]*"Dropped fine-grained regexp-based parsing of displayspecs. 1.28defsubstdatabase-empty-pIncorporated into callers. 1.28defundatabase-recordfieldspecReturn the recordfieldspec of DB corresponding to SEL. If SEL is a number, it is taken as the record index. If it is a symbol, it names a field in the record. Dereferences any symbol found in the recordfieldspecs slot of DATABASE. Dropped non-slice access to a db's recordfieldspecs. 1.28defundatabase-recordfieldspec-typeReturn the type of the recordfieldspec of DB corresponding to IDX, a record index.Incorporated into unique caller. 1.28defundatabase-set-recordfieldspecSet the recordfieldspec of DB corresponding to SEL to RS. If SEL Is a number, it is taken as the record index. If it is a symbol, it names a field in the record. Use this to redefine, on a per-field basis, subfields of the recordfieldspec. Incorporated into callers. 1.28defundb-string->displaytypeReturn the displaytype (a symbol) corresponding to string S. Non-strings are returned unchanged. This doesn't work yet for multichar alternatives. Dropped "abbreviation" displayspecs. Converted callers to use `intern'. 1.28defundbf-fill-summary-buffer-and-move-to-proper-recordConverted callers to use `dbf-fill-summary-buffer' with non-nil MOVEP. 1.28defunedb--field-nm2noIncorporated into callers. 1.27defaliasdb-commit-recordUnused. Alias target `db-accept-record' still provided. 1.27defaliasrecord-fieldReplaced by `db-record-field'. 1.27defaliasrecord-set-fieldReplaced by `db-record-set-field'. 1.27defconstedb-t-timedate1:format-date-mmddyy-separator"/"A string used to separate the components of the MMDDYY date format.Converted callers to use optional arg SEPARATOR. 1.27defconstedb-t-timedate1:format-date-yymmdd-separator""A string used to separate the components of the DDMMYY date format.Converted callers to use optional arg SEPARATOR. 1.27defconstedb-t-timedate1:format-date-yyyymmdd-separator"/"A string used to separate the components of the YYYY/MM/DD date format.Converted callers to use optional arg SEPARATOR. 1.27deflocalvardbf-reset-on-edit-listnilAn alist of (variable-name . default-value) pairs. Every time Database Edit mode is entered, these buffer-local variables are reset to their default values. This is good for making sure that something only happens once each time a record is edited.Unused. Similar functionality can be arranged through `db-edit-mode-hooks'. 1.27defmacrodeflocalvarLike defvar, but defines a buffer-local variable.Unused. Variables that were declared w/ this form are now declared w/ `defvar' and made buffer-local at runtime. 1.27defsubstdb-tagged-helpIncorporated into unique caller. 1.27defsubstdb-tagged-nameIncorporated into unique caller. 1.27defsubstdb-tagged-tagIncorporated into unique caller. 1.27defsubstedb--TUnused. 1.27defsubstedb--T!Unused. 1.27defsubstmake-recordReplaced by `db-make-record'. 1.27defundb-convertConvert DB's field structure according to FCREATE-SPECS. This function rearranges the field order, converts fields from one type to another, adds or removes fields, and so forth. Note that this does not create a new database; it destructively changes the format of DATABASE. FCREATE-SPECS is a list of two-element lists of the form: (fieldnames creation-method) If creation-method would be nil, then fieldname alone may be used in place of the two-element list.Unused. 1.27defundb-tagged-rrfrConverted unique caller to use `db-tagged-read'. 1.27defundb-tagged-wrfrConverted unique caller to use `db-tagged-write'. 1.27defundefine-displaytype-from-optstringDefine a displaytype named NAME according to OPTSTRING. NAME is a symbol or string and OPTSTRING is the optional parameters part of a display specification string.Unused. 1.27defundefine-one-char-enum-displaytypeNot yet implemented.Unused. Also, unimplemented. 1.27defundefine-type-aliasMake ALIAS refer to the same displaytype and recordfieldtype as TYPE. ALIAS is a symbol.Unused. 1.27defvaredb-t-timedate1:format-date-ddmmmyy-separator" "A string used to separate the components of the DD MMM YY date format.Converted callers to use optional arg SEPARATOR. 1.27defvaredb-t-timedate1:format-date-ddmmyy-separator"."A string used to separate the components of the DDMMYY date format.Converted callers to use optional arg SEPARATOR. 1.26defconstdb-dsrx(concat "\\(" (concat "\\\\" db-symbol-regexp) "\\)" (concat "\\(" db-foptrx "\\)*") "\\(\\\\ \\)?")Converted refs to use `db-dsym'. 1.26defconstdb-dsrx-content-beginningdb-dsrx-fieldnameConverted refs to use `db-dsym'. 1.26defconstdb-dsrx-content-end0Converted refs to use `db-dsym'. 1.26defconstdb-dsrx-content-end-altdb-dsrx-fieldnameConverted refs to use `db-dsym'. 1.26defconstdb-dsrx-fieldname1Converted refs to use `db-dsym'. 1.26defconstdb-dsrx-fieldoptions2Converted refs to use `db-dsym'. 1.26defconstdb-foptrx(concat db-dtrx "\\(=\\(" "[-<>a-zA-Z0-9]+" "\\)\\)?")Converted refs to use `db-fopt'. 1.26defconstdb-foptrx-equals3Converted refs to use `db-fopt'. 1.26defconstdb-foptrx-symbol1Converted refs to use `db-fopt'. 1.26defconstedb-date"@EDB-DATE@"Incorporated value into function `edb-version'. 1.26defconstedb-essential-file-names'("db-rep" "db-format" "db-file-io" "db-interfa" "db-types" "db-summary")Dropped runtime byte-compilation support. 1.26deflocalvardb-for-outputnilDefault database to which to output records.Converted to :db-for-output. 1.26deflocalvardbc-database-modified-pnilT if the database has been modified, nil otherwise. Mirrors the value of the modified-p slot of the database. This has to be a real variable so it can go in mode-line-format. Set it using `dbc-set-database-modified-p'.Converted to :dbmodp. 1.26deflocalvardbc-hide-pnilNon-nil if hiding is in effect, nil otherwise. Use function `dbc-set-hide-p', which works in either a data display buffer or a summary buffer and sets the variable's value in both, instead of setting this directly. Setting this to nil is cheaper than changing the hide function to the empty one, since no hide bits are recomputed. This variable is automatically set by the hiding functions.Converted to :hide-p. 1.26deflocalvardbc-indexnilThe index of the record currently being displayed (and of its link), or nil. Use `dbc-set-index' to set this value unless you know what you are doing.Converted to :index. 1.26deflocalvardbc-index-fractionnilA string of the form dbc-index/database-no-of-records. Variables with numeric values aren't allowed in mode-line-format. An asterisk (*) precedes dbc-index if the current record is marked. The fraction is surrounded by square brackets if the current record is hidden. This variable should only be set by calling `dbc-set-index'.Converted to :index-fraction. 1.26deflocalvardbc-linknilThe link of the record currently being displayed, or nil.Converted callers to use the record directly. 1.26deflocalvardbc-wraparound-p'delayValue t, nil, or 'delay determines whether going forward from the last record (or backward from the first) wraps, is prohibited, or denies on the first attempt only and then wraps.Converted to :wraparound-p. (Starting with 1.27, :wraparound-p was renamed to :wraparound, since it can have three valid values.) 1.26deflocalvardbf-after-display-record-hooknilHooks called after a record is displayed. The hooks are called in the data display buffer. Call `dbf-displayed-record' to get the just-displayed record.Unused. Converted unique caller to no longer run the hook. Face customization et al will probably return later. 1.26deflocalvardbf-always-formsnilForms executed every time that the format is selected. These forms are only executed when a different format is replaced, not every time that a record is displayed (or even every time that `db-change-format' is called). See also `dbf-before-display-record-function'.Converted to :always-forms. 1.26deflocalvardbf-change-functionsnilA vector of one function (or nil) per record field (not display field). The functions take the fieldname and the old and new values as arguments, and return t if the record should be redisplayed. Use `dbf-set-change-function' to set the fields of this vector.Converted to :change-functions. 1.26deflocalvardbf-default-field-facenilIf non-nil, the face for fields in data display buffers. If the text already has a face, that takes precedence. This variable is examined only when a data display buffer is being set up.Unused. 1.26deflocalvardbf-default-inter-field-facenilIf non-nil, the face for uneditable text in data display buffers. If the text already has a face, that takes precedence. This variable is examined only when a data display buffer is being set up.Unused. 1.26deflocalvardbf-displayspecs-lengthnilThe number of displayspecs in the current format.Converted callers to use `(length dbf-displayspecs)' directly. 1.26deflocalvardbf-field-boundary-action'errorControls action when point attempts to leave a field. One of nil, 'message, 'beep, 'ding, 'error. 'beep and 'ding are identical and also show a message. Having a variable is overkill, but I don't yet know what the Right Thing is.Dropped customizable handling of move-out-of-field condition. This may return later. 1.26deflocalvardbf-field-prioritiesnilList of field priorities for this database in this data display buffer. If non-nil, overrides the database's field-priorities slot.Converted to :field-priorities. No scadenza: Not used in any examples. 1.26deflocalvardbf-field-search-defaultsnilVector of defaults for field search. It is one element longer than the number of fields; the element indexed by dbf-displayspecs-length is the default for a search over all fields.Converted to :search-defaults. 1.26deflocalvardbf-fields-displayednilA vector of one string, the displayed text for that field, per displayspec.Converted to :shown. 1.26deflocalvardbf-format-filenilThe format file from which the current format was built.Converted to :format-file. 1.26deflocalvardbf-format-file-spec-alistnilAssociation list of file names and format file specifiers. A format file specifier is a list of values for format variables. Don't set this variable; use `dbf-format-name-spec-alist' instead.Converted to :fmtspec-stash. 1.26deflocalvardbf-format-namenilThis buffer-local string names the format currently in use. This should not be set by the user.Converted to :format-name. 1.26deflocalvardbf-hidden-to-end-pnilThe default, local to this data display buffer, for the hidden-to-end-p bit. Only used if a local value of field priorities is used.Dropped support for noninteractive specification. 1.26deflocalvardbf-inter-field-textnilA vector with one string, the constant text that precedes that field in the display, per displayspec, plus a final slot for trailing text.Converted to :iftxt. 1.26deflocalvardbf-recordindex-displayspecno-vectornilVector used to translate displayspec index to field index.Converted to :fidx2dsidx. 1.26deflocalvardbf-selected-field-facenilIf non-nil, the face for the field being currently edited.Unused. 1.26deflocalvardbf-stay-in-edit-mode-pt*Whether edit mode is preserved when switching records in EDB. Automatically becomes local to the current buffer when set in any fashion. Only has an effect when set in an EDB data display buffer.Converted to :stay-in-edit-mode-p. 1.26deflocalvardbf-summary-buffernilThe summary buffer associated with this format.Converted to :sumbuf. 1.26deflocalvardbf-summary-formatnilA string in the same format as the format-file. Use `dbf-set-summary-format' to set it.Converted to :sumfmt. 1.26deflocalvardbf-summary-functionnilFunction which inserts summary information for a single record in the summary buffer; it takes the record as its argument.Converted to :sumfun. 1.26deflocalvardbf-summary-recompute-all-pnilT if every record summary in this buffer should be recomputed.Converted callers to use :summaries. 1.26deflocalvardbf-summary-show-hidden-records-ptNil if hidden records should be hidden from the summary, t otherwise.Converted to :invisible-hidden-p. 1.26deflocalvardbf-this-displayspecnilThe displayspec currently being operated upon, or nil.Converted to :this-ds. 1.26deflocalvardbf-this-field-beginning-posnilA position, the beginning of the current field.Converted to :fbeg. 1.26deflocalvardbf-this-field-end-marker(make-marker)A mark one character past the end of the current field, or nil if current field extends to end of buffer.Converted to :fend. 1.26deflocalvardbf-this-field-indexnilThe index in `dbf-displayspecs' of the current displayspec, or nil.Converted to :this-fidx. 1.26deflocalvardbf-this-recordnilThe record currently displayed and edited. This is an honest-to-goodness record whose slots are filled from `:original' if it's modified. The variable's value should never be set except by `db-copy-r2r'; its slots may be freely modified, however. This is only used if `:utkmodp' is t.Converted to :under. 1.26deflocalvardbf-this-record-modified-pnilT if the current record has been modified, nil otherwise. This determines which record is returned by `dbf-displayed-record': if non-nil, then `dbf-this-record-original' has been copied to `dbf-this-record'. It's best to use `dbf-set-this-record-modified-p' to set this variable.Converted to :utkmodp. 1.26deflocalvardbf-this-record-originalnilThe original of `dbf-this-record'; a pointer to some poor unsuspecting record that shouldn't be modified until everything has been checked out. That is, when the user is setting fields, this record remains unchanged and `dbf-this-record', a copy of the original, is munged instead.Converted to :original. 1.26deflocalvardbfs-linesnilThe (constant) number of screen lines occupied by each record summary. This variable is computed automatically from the summary format. It has a value in both the summary and data display buffers.Converted to :sum1lines in global hash. 1.26deflocalvardbs-data-display-buffernilThe buffer of the format for which this buffer is a summary.Converted to :data-display-buffer. 1.26deflocalvardbs-indexnilThe index of the record summary at point. Used in determining whether the data display buffer and its summary are in synch. Don't set this variable directly; use `dbs-set-index' instead.Converted to :index. 1.26deflocalvardbs-index-fractionnilLike `dbc-index-fraction', for the benefit of the mode line.Converted callers to use `dbc-index-fraction'. 1.26deflocalvardbs-no-of-recordsnilThe number of records in the database when this summary was made.Converted to :nrecords. 1.26deflocalvardbs-pointnilThe beginning of the current record.Converted to :point. 1.26deflocalvardbs-recompute-pnilT if some summary information is out of date, nil otherwise. This is usually set to t when some link-summary is set to nil.Converted to :recompute-p. 1.26deflocalvardbsi-data-display-buffernilConverted to :ddb. 1.26deflocalvardbsi-databasenilConverted callers to use `dbc-database'. 1.26deflocalvardbsi-hidden-to-end-pnilThe hidden-to-end slot of the database will be set from this variable.Converted to :hendp. 1.26deflocalvardbsi-killed-fieldsnilConverted to :killed. 1.26deflocalvardbsi-nonsig-fieldsnilConverted to :non. 1.26deflocalvardbsi-sig-fieldsnilConverted to :sig. 1.26defmacrodb-actual->display-callConverted callers to use `db-callconvert'. 1.26defmacrodb-display->actual-callConverted callers to use `db-callconvert'. 1.26defmacrodb-lmap-breakCause the db-lmap loop to quit after executing the current iteration. This is not a nonlocal exit! It sets a flag which prevents future iterations. (Actually, it sets variable `db-lmap-link'.)Unused. Dropped support for breaking out of `maprecords'. 1.26defmacrodb-lmap-macroExecute LMAP-BODY for each link in DATABASE, and return nil. If optional third arg HIDE is non-nil, execute LMAP-BODY only for unhidden links. If optional fourth arg MESSAGE is non-nil, it should be a format string containing one numeric (%d) specifier. That message will be issued every `db-inform-interval' links. In the body, variable `db-lmap-link' is bound to the link being operated upon, and `db-lmap-index' is bound to its index. The loop may be short-circuited (aborted) by calling `db-lmap-break'. Speed demons should call this instead of `db-lmap' to avoid a function call overhead per link.Unused. 1.26defmacrodb-vararg-callApply FUNC to NARGS1 (an integer), then (if that fails), to NARGS2 of the ARGS. -1 means all arguments. This macro lets you deal with functions expecting different numbers of arguments in a uniform way. Since this is a macro, don't supply something of the form (function foo) as its first argument; just supply foo itself.Unused. 1.26defmacrodb-with-pcPC is previous-cons.Dropped separate "killed fields" data structure. 1.26defmacrodb-with-pc-and-tiPC is previous-cons; TI is this-item.Dropped separate "killed fields" data structure. 1.26defmacrodbf-in-summary-bufferExecute BODY in the summary buffer, if it exists.Converted callers to use `with-current-buffer' or `db-in-buffer'. 1.26defmacrodbs-in-data-display-bufferExecute BODY in the data display buffer (which always exists).Converted callers to use `with-current-buffer' or `db-in-buffer'. 1.26defstructedb--v1-linkUnused. 1.26defsubstdatabase-set-alternative-sepinfoExplicit setter for `alternative-sepinfo' in `edb--v1-monolithic-mess'.Unused. Also deleted: `alternative-sepinfo' slot. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-aux-fileExplicit setter for `aux-file' in `edb--v1-monolithic-mess'.Unused. Also deleted: `aux-file' slot. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-data-display-buffersExplicit setter for `data-display-buffers' in `edb--v1-monolithic-mess'.Unused. Also deleted: `data-display-buffers' slot. Converted to :ddbufs in global hash. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-default-format-fileExplicit setter for `default-format-file' in `edb--v1-monolithic-mess'.Unused. Also deleted: `default-format-file' slot. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-field-sepinfoExplicit setter for `field-sepinfo' in `edb--v1-monolithic-mess'.Unused. Slot is read-only. 1.26defsubstdatabase-set-fieldname-alistExplicit setter for `fieldname-alist' in `edb--v1-monolithic-mess'.Unused. Also deleted: `fieldname-alist' slot. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-fileExplicit setter for `file' in `edb--v1-monolithic-mess'.Unused. Also deleted: `file' slot. Converted to :file in global hash. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-file-local-variablesExplicit setter for `file-local-variables' in `edb--v1-monolithic-mess'.Unused. Also deleted: `file-local-variables' slot. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-first-linkExplicit setter for `first-link' in `edb--v1-monolithic-mess'.Unused. Also deleted: `first-link' slot. Converted callers to use :vov in global hash. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-hidden-to-end-pExplicit setter for `hidden-to-end-p' in `edb--v1-monolithic-mess'.Unused. Also deleted: `hidden-to-end-p' slot. Converted to :hendp in global hash. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-hide-functionsExplicit setter for `hide-functions' in `edb--v1-monolithic-mess'.Unused. Also deleted: `hide-functions' slot. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-internal-file-layout-pExplicit setter for `internal-file-layout-p' in `edb--v1-monolithic-mess'.Unused. Also deleted: `internal-file-layout-p' slot. Converted to :togp in global hash. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-modifiable-pExplicit setter for `modifiable-p' in `edb--v1-monolithic-mess'.Unused. Also deleted: `modifiable-p' slot. Converted to :modifiable-p in global hash. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-no-of-fieldsExplicit setter for `no-of-fields' in `edb--v1-monolithic-mess'.Unused. Also deleted: `hide-functions' slot. Converted callers to use field count directly. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-no-of-recordsExplicit setter for `no-of-records' in `edb--v1-monolithic-mess'.Unused. Also deleted: `no-of-records' slot. Converted to :nrecords in global hash. Added handling for 0.6 to 0.7 "internal format" edits. 1.26defsubstdatabase-set-record-sepinfoExplicit setter for `record-sepinfo' in `edb--v1-monolithic-mess'.Unused. Slot is read-only. 1.26defsubstdb-confls-fieldsep-bad-pConverted callers to use `db-conftup-bad-fsep'. 1.26defsubstdb-confls-no-of-recordsConverted callers to use `db-conftup-reccount'. 1.26defsubstdb-confls-recordsep-bad-pConverted callers to use `db-conftup-bad-rsep'. 1.26defsubstdb-data-display-bufferReturn the database data display buffer associated with the current buffer, which must be either a summary buffer or a data display buffer.Converted unique caller to use :data-display-buffer. 1.26defsubstdb-rdb-pNon-nil if DB is in RDB file layout.Incorporated into callers. 1.26defsubstdb-select-last-recordSelect last record. Does no display. If hiding is in effect, select the last unhidden record, unless optional argument IGNORE-HIDING is non-nil.Unused. 1.26defsubstdb-select-prev-recordAdvance to the ARGth previous record. Does no display.Unused. 1.26defsubstdb-skip-regexp-backwardIf point is after regexp RX, move past it and return point; otherwise return nil. Incorporated into unique caller. 1.26defsubstdb-summary-bufferReturn the database summary buffer associated with the current buffer, which must be either a summary buffer (which is returned) or a data display buffer. Return nil if there is no associated summary buffer.Converted to :sumbuf. 1.26defsubstdb-tagged-pNon-nil if DATABASE is in tagged file layout.Incorporated into callers. 1.26defsubstdbc-set-database-modified-pConverted callers to use :modp in global hash. 1.26defsubstdbc-update-database-modified-pConverted callers to use :modp in global hash. 1.26defsubstdbf-point-minConverted callers to use `point-min'. 1.26defsubstdbf-summary-bufferConverted callers to use :sumbuf. 1.26defsubstdbf-this-field-beginning-posUnused. 1.26defsubstdisplayspec-set-actual->displayExplicit setter for `actual->display' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-display->actualExplicit setter for `display->actual' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-indentExplicit setter for `indent' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-match-actual->displayExplicit setter for `match-actual->display' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-match-display->actualExplicit setter for `match-display->actual' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-max-bytesExplicit setter for `max-bytes' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-max-heightExplicit setter for `max-height' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-max-widthExplicit setter for `max-width' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-min-bytesExplicit setter for `min-bytes' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-min-heightExplicit setter for `min-height' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-min-widthExplicit setter for `min-width' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-padding-actionExplicit setter for `padding-action' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-reachablepExplicit setter for `reachablep' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-record-indexExplicit setter for `record-index' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-truncation-display-actionExplicit setter for `truncation-display-action' in `edb--v1-ds'.Unused. 1.26defsubstdisplayspec-set-truncation-editing-actionExplicit setter for `truncation-editing-action' in `edb--v1-ds'.Unused. 1.26defsubstfieldname->fieldnumberGiven a FIELDNAME and DATABASE, return a record fieldnumber. Do not be fooled into thinking this is a format fieldnumber.Converted callers to use `edb--field-nm2no'. 1.26defsubstlink-set-hiddenpExplicit setter for `hiddenp' in `edb--v1-link'.Unused. Also deleted: `hiddenp' slot. Converted callers to use :hiddenp tag. 1.26defsubstlink-set-markedpExplicit setter for `markedp' in `edb--v1-link'.Unused. Also deleted: `markedp' slot. Converted callers to use :markedp tag. 1.26defsubstlink-set-nextExplicit setter for `next' in `edb--v1-link'.Unused. Also deleted: `next' slot. Converted callers to use :vov. 1.26defsubstlink-set-prevExplicit setter for `prev' in `edb--v1-link'.Unused. Also deleted: `prev' slot. Converted callers to use :vov. 1.26defsubstlink-set-recordExplicit setter for `record' in `edb--v1-link'.Incorporated into callers. 1.26defsubstlink-set-summaryExplicit setter for `summary' in `edb--v1-link'.Unused. Also deleted: `summary' slot. Converted callers to use :summaries, :nrecords, :recompute-p and :point. 1.26defsubstrecord-field-from-indexReturn from RECORD the value of the FIELDNOth field.Converted callers to use `aref'. 1.26defsubstrecord-set-field-from-indexSet, in RECORD, the FIELDNOth field to VALUE. Checks field constraints first if DATABASE is non-nil.Converted callers to use `aset' and `db-check-constraint'. 1.26defsubstrecordfieldspec-set-actual->storedExplicit setter for `actual->stored' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-change-hookExplicit setter for `change-hook' in `edb--v1-rs'.Unused. Also deleted: `change-hook' slot. 1.26defsubstrecordfieldspec-set-common-form-functionExplicit setter for `common-form-function' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-constraint-functionExplicit setter for `constraint-function' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-default-valueExplicit setter for `default-value' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-help-infoExplicit setter for `help-info' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-match-functionExplicit setter for `match-function' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-merge-functionExplicit setter for `merge-function' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-order-fnExplicit setter for `order-fn' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-order-functionExplicit setter for `order-fn' (sic) in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-sort-fnExplicit setter for `sort-fn' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-sort-functionExplicit setter for `sort-fn' (sic) in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-stored->actualExplicit setter for `stored->actual' in `edb--v1-rs'.Unused. 1.26defsubstrecordfieldspec-set-typeExplicit setter for `type' in `edb--v1-rs'.Unused. 1.26defundatabase-check-sepinfoIncorporated into unique caller. 1.26defundatabase-clean-data-display-buffersRemove killed buffers from DATABASE's data-display-buffers slot. Return a list of the remaining data display buffers. If there are none, kill DATABASE as well.Converted callers to use :ddbufs in global hash. Dropped re-entrant buffer-killing mechanism. 1.26defundatabase-delete-pre-and-postModify current buffer according to DATABASE. Remove pre-first-record- and post-last-record strings or regexps, then add a field separator to the end so that every record is terminated by one.Incorporated into unique caller. 1.26defundatabase-set-links-from-listTake a list of links, set `database-first-link' to the first one and set `link-next' and `link-prev' of each such that all the links are arranged in a doubly-linked list in the order of the list. Converted callers to use `edb--snap!'. 1.26defundatabase-substitute-for-readIncorporated into unique caller. 1.26defundatabase-substitute-for-writeIncorporated into unique caller. 1.26defundb-best-fit-messageShow TEXT in echo area if it fits or in optional BUF (default *Message*).Converted callers to use `message'. 1.26defundb-canonicalize-creation-methodIncorporated into unique caller. 1.26defundb-convert-compute-field-valueIncorporated into unique caller. 1.26defundb-convert-recordCreate and return a new record from RECORD using METHODS, a list of canonical creation methods. Optional argument NO-OF-FIELDS gives the length of METHODS and the number of fields in the result record. Dynamically binds db-computed-functions. Incorporated into unique caller. 1.26defundb-file->format-fileReturn a format file or nil.Incorporated into unique caller. 1.26defundb-funcall-maybeIf FUN is non-nil, apply it to ARGS. Otherwise return second argument, which would have been the first argument to which FUN was applied. FUN should be a funcallable object or nil. Incorporated into callers. 1.26defundb-join-linksPlace LINK1 and LINK2 in a prev-next relationship.Unused. 1.26defundb-kill-buffersKill this buffer, and the associated summary or data display buffer, if any. If its last data display buffer is killed, the database is killed too. Does not offer to save changes to the database or to this record; use `db-exit' with optional argument to do so.Dropped re-entrant buffer-killing mechanism. 1.26defundb-new-linkUnused. 1.26defundb-next-link-and-indexArguments DATABASE LINK IDX N HIDEP MARKP WRAPAROUNDP. Return a list of (link index) for Nth successor of LINK, whose index in the database is IDX. N may be negative. If MARKEDP is non-nil, find the Nth marked successor of LINK. If HIDEP is non-nil, skip hidden links. If WRAPAROUNDP is nil, stop at the first or last candidate link (ie, properly marked and/or non-hidden, or LINK itself if no such encountered); if the end of the database stops the search in this way, the returned list also contains a third element, the number of elements yet to go. Incorporated into unique caller. 1.26defundb-save-database-helperIncorporated into unique caller. 1.26defundbf-fieldname->displayspecnoUnused. 1.26defundbf-make-format-specIncorporated into unique caller. 1.26defundbf-make-summary-makerIncorporated into unique caller. 1.26defundbsi-killed-fields-to-end-maybeConverted callers to use `dbsi-ordering<-buffer'. 1.26defundbsi-prev-consDropped separate "killed fields" data structure. 1.26defunedb-byte-compile-allDropped runtime byte-compilation support. 1.26defvardatabases-made0Converted to :databases-made property of symbol `edb'. 1.26defvardb-computed-functionsnilWas used dynamically. Retired along with `db-convert-compute-field-value'. 1.26defvardb-databasesnilAssoc list of database names and databases.Converted to :1singles in EDB hash. 1.26defvardb-displaytypes(make-hash-table)Hash associating type names (symbols) and displayspecs.Converted to :1displaytypes in EDB hash. 1.26defvardb-dt-leading-comma-optionalnilNon-nil if symbolic displaytypes may immediately follow a fieldname. Nil if a comma must come between the fieldname and the displaytype symbol. Displaytype symbols include # $ \" '. When this is non-nil, then sometimes Emacs 19 searches are intolerably slow.Incorporated value as-is. 1.26defvardb-io-error-pnilNon-nil if there has been an error while reading or writing the database.Converted to :io-error-p in EDB hash. 1.26defvardb-kill-buffer-hook-inhibit-pnilNon-nil if `db-kill-buffer-hook' shouldn't do anything.Dropped re-entrant buffer-killing mechanism. 1.26defvardb-lmap-linkThe current link in a call to `db-lmap' or `db-lmap-macro'.Unused. 1.26defvardb-load-hooksnilFunction or list of functions run after loading EDB. You can use this to load extensions, redefine EDB functions, customize key bindings, etc.Dropped special-cased load-hooks handling. 1.26defvardb-mention-filename-on-save-ptNon-nil if a database's print-name or filename should be mentioned when it is saved to disk.Incorporated value as-is, eliding conditional at ref site. Perhaps this kind of customization will return later in a different form w/ message catalog extraction. 1.26defvardb-rdb-converted-pnilNon-nil if `database-stored->actual' has already been run.Converted to :rdb-converted-p. 1.26defvardb-rdb-field-defsnilSet to the field definitions computed from the programmer-supplied field definitions and the RDB header field definitions.Converted to :rdb-field-defs. 1.26defvardb-rdb-field-name-charset"a-zA-Z0-9_"The characters allowed in an RDB field name (using regexp format sans "[]").Incorporated value as-is. 1.26defvardb-rdb-file-typenilSet to 'list or 'table by rdb-read-fields according to the type of the file. This is a database-local variable.Converted to :file-type. 1.26defvardb-rdb-header-fieldsnilSet to the list of header fields parsed by `db-rdb-read-fields'.Converted to :header-fields. 1.26defvardb-rdb-header-stringnilSet to the header string, for either List or Table RDB files. This is used to rewrite the header when the database is updated.Converted to :header-string. 1.26defvardb-rdb-list-continuation-outputnilA computed string used to identify and align continuation data.Converted to :list-continuation-output. 1.26defvardb-rdb-list-continuation-regexp"^[ \t]*|[ \t]+"A regexp which matches the beginning of a List-format entry continuation.Converted to :list-continuation-regexp. 1.26defvardb-rdb-list-entry-regexp(concat "[ \t]*\\([" db-rdb-field-name-charset "]*\\)" (regexp-quote db-rdb-list-separator-string) "[ \t]*")A regexp which matches the beginning of a List-format field entry, grouping the field name as \1.Converted to :list-entry-regexp. 1.26defvardb-rdb-list-separator-string" | "The string that separates field names from values.Incorporated value as-is. 1.26defvardb-rdb-rrfr-hooksnilHooks run on each database record before RDB parse.Converted to :pre-parse-thunk. 1.26defvardb-rdb-wrfr-after-hooksnilHooks run after each RDB write of a database record. The record is bound to the dynamic variable `record', and point is immediately after the file representation of the record.Converted to :post-write-function. 1.26defvardb-rdb-wrfr-before-hooksnilHooks run before each RDB write of a database record. The record is bound to the dynamic variable `record', and point is where the record will be inserted in the buffer.Converted to :pre-write-function. 1.26defvardb-recordfieldtypes(make-hash-table)Hash associating type names (symbols) and recordfieldspecs.Converted to :1recordfieldtypes in EDB hash. 1.26defvardb-substitution-no-no-stringnilGlobal; hope we only write/read one database at a time. It should be reset before starting to read/write a database.Converted to :substitution-no-no in global hash. 1.26defvardb-tagged-continuation"\t"The string that marks (the beginning of) a continuation line. Used only if `db-tagged-continuation-regexp' or `db-tagged-continuation-output' is nil (depending on whether the record is being read or written).Converted to :continuation. 1.26defvardb-tagged-continuation-outputnilThe fixed string to use (before) continuing values on output.Converted to :continuation-output. 1.26defvardb-tagged-continuation-regexp"[ \t]+"A regexp for a continuation line in a value when parsing.Converted to :continuation-regexp. 1.26defvardb-tagged-converted-pnilNon-nil if `database-stored->actual' has already been run.Converted to :tagged-converted-p. 1.26defvardb-tagged-default-fieldnilA fieldname (symbol) for the field indicated by an illegal or empty tag. (For instance, you might set it to 'comments.) Nil if those values should be discarded.Converted to :default-field. 1.26defvardb-tagged-pre-tag""The string that precedes each tag. Used only if `db-tagged-pre-tag-regexp' or `db-tagged-pre-tag-output' is nil (depending on whether the record is being read or written).Converted to :pre-tag. 1.26defvardb-tagged-pre-tag-outputnilThe fixed string to place before each tag on output.Converted to :pre-tag-output. 1.26defvardb-tagged-pre-tag-regexpnilA regexp for what precedes each tag on its line when parsing. It must NOT contain any grouping constructs.Converted to :pre-tag-regexp. 1.26defvardb-tagged-rrfr-hooksnilHooks run on each database record before tagged parse.Converted to :pre-parse-thunk. 1.26defvardb-tagged-separator":"The string that separates field names from values. Used only if `db-tagged-separator-regexp' or `db-tagged-separator-output' is nil (depending on whether the record is being read or written).Converted to :separator. 1.26defvardb-tagged-separator-outputnilThe separator between field names and values on output.Converted to :separator-output. 1.26defvardb-tagged-separator-regexpnilA regexp for the separator between field names and values when parsing.Converted to :separator-regexp. 1.26defvardb-tagged-tag-chars"-_A-Za-z"The characters that are allowed in field tags, in a form suitable for placing inside [] in a regular expression.Converted to :tag-chars. 1.26defvardb-tagged-wrfr-after-hooksnilHooks run after each tagged write of a database record. The record is bound to the dynamic variable record, and point is immediately after the file representation of the record.Converted to :post-write-function. 1.26defvardb-tagged-wrfr-before-hooksnilHooks run before each tagged write of a database record. The record is bound to the dynamic variable record, and point is where the record will be inserted in the buffer.Converted to :pre-write-function. 1.26defvardbc-deleted-recordnilThe record most recently deleted by `db-delete-record'.Converted to :deleted-record in global hash. 1.26defvardbf-default-summary-formatnilConverted to :default-sumfmt. 1.26defvardbf-minor-modenilA symbol, either 'view or 'edit.Dropped implementation of View vs Edit as minor modes. 1.26defvardbf-minor-mode-namenil"View" or "Edit".Dropped implementation of View vs Edit as minor modes. 1.26defvardbf-moving-mark(make-marker)Converted to :1moving-mark in EDB hash. 1.26defvardbm-string-regexp-prefix"^[ \t]*\\(/\\|regexp[ \t]+\\)"Incorporate value as-is. 1.26defvardbm-string-regexp-prefix-string"/"Incorporate value as-is. 1.26fsetmaprecords-breakdb-lmap-breakUnused. Dropped support for breaking out of `maprecords'. 1.25defaliasdb-string->number-defaultdb-string->integer-defaultUnused. 1.25defaliasrecordfieldspec-order-functiondb-rs-ordfuncAnnounced scadenza. 1.25defaliasrecordfieldspec-sort-functiondb-rs-sortfuncAnnounced scadenza. 1.25defmacromaprecords-macroExecute MAPRECORDS-BODY for each record in DATABASE, and return nil. If optional third arg HIDE is non-nil, execute MAPRECORDS-BODY only for unhidden records. If optional fourth arg MESSAGE is non-nil, it should be a format string containing one numeric (%d) specifier. That message will be issued every `db-inform-interval' links. In the body, variable `maprecords-record' is bound to the record being operated upon. The loop may be short-circuited (aborted) by calling `maprecords-break'. See also `maprecords'.Unused. 1.25defsubstcopy-recordReturn a copy of RECORD.Unused. 1.25defundb-string->integer-defaultIf string S represents an integer, return it; otherwise return DEFAULT.Incorporated into unique caller. 1.25defunmake-displayspec-from-stringCreate a displayspec from specification string S. Second argument is DATABASE.Unused. 1.24defconstdb-elt-separator-regexpIncorporated value as-is. 1.24defconstdisplaytype-nonsymbol-regexp"#\\|\\$\\|\"\\|'\\|\\[[^]]+\\]"Incorporated value as-is. 1.24defconstdoubled-backslash-regexp"\\(\\\\\\\\\\)*"Regular expression which matches any number of pairs of backslashes. Usually used in conjunction with other regexps.Incorporated value as-is. 1.24defconstedb-autoloaded-file-names'("db-convert" "db-isbn" "db-rdb" "db-search" "db-sort" "db-summary" "db-tagged" "db-two-dbs")List of EDB source files loaded by `autoload', sans extensions.Incorporated value as-is. 1.24defconstedb-file-names(append edb-required-file-names edb-essential-file-names edb-autoloaded-file-names)List of all EDB source files, sans extensions. Does not include "database", the top-level file.Incorporated value as-is. 1.24defconstedb-required-file-names'("db-util")List of EDB source files loaded by `require', sans extensions.Incorporated value as-is. 1.24defconstedb-source-file-names(mapcar (lambda (file-name) (concat file-name ".el")) edb-file-names)Incorporated value as-is. 1.24defconstfieldname-regexp(concat "\\\\" symbol-regexp)Incorporated value as-is. 1.24defconstfieldoptions-regexp(concat "\\(" fieldoption-regexp "\\)*")Incorporated value as-is. 1.24defconstfull-year-regexpIncorporated value as-is. 1.24defconstmonthday-regexpIncorporated value as-is. 1.24defconstmonthday-regexp-two-charIncorporated value as-is. 1.24defconstmonthlength-arrayIncorporated value as-is. 1.24defconstmonthname-regexpIncorporated value as-is. 1.24defconstmonthnumber-regexpIncorporated value as-is. 1.24defconstmonthnumber-regexp-two-charIncorporated value as-is. 1.24defconstnon-backslash-character-regexp"\\(^\\|[^\\]\\)"Incorporated value as-is. 1.24defconstshort-year-regexpIncorporated value as-is. 1.24defconstsymbol-or-number-regexp"[-<>a-zA-Z0-9]+"Incorporated value as-is. 1.24defconstweekday-alistIncorporated value as-is. 1.24defconstweekday-arrayIncorporated value as-is. 1.24defconstweekday-regexpIncorporated value as-is. 1.24defconstyear-regexpIncorporated value as-is. 1.24deflocalvardbf-wraparound-ptValue t, nil, or 'delay determines whether going forward from the last field (or backward from the first) wraps, is prohibited, or delays. 'delay has the effect of prohibiting such movement the first time, but if the user immediately makes a second attempt, that one is successful. Somewhat analogous to dbc-wraparound-p.Unused. 1.24defmacrodb-debugExecute BODY if `db-debug-p' is non-nil. See also variable `db-disable-debugging-support'.Dropped special debugging support altogether. 1.24defmacrodb-debug-logUnused. 1.24defmacrodb-debug-messageConverted callers to no longer output debugging messages. 1.24defmacromapfieldsApply FUNC to each field in RECORD, with variable `mapfields-index' bound. Third argument is DATABASE.Dropped support for mapping over fields. 1.24defmacromapfields-macroExecute BODY for each field of RECORD, a record of DATABASE, with variables `mapfields-field' and `mapfields-index' bound.Dropped support for mapping over fields. 1.24defmacrowith-electric-help-maybeSimilar to `with-electric-help' if `use-electric-help-p' is non-nil; otherwise like `with-output-to-temp-buffer' with the "*Help*" buffer. Ehelp is loaded if necessary. BODY is not a thunk (a function of no arguments), as with `with-electric-help', but simply a set of forms.Converted unique caller to use `with-output-to-temp-buffer'. 1.24defsubstcountrypThis kind of information may return later as part of some type library (edb-t-FOO.el file). 1.24defsubstcreation-method-literal-pIncorporated into callers. 1.24defsubstdata-display-buffer-databaseUnused. 1.24defsubstdatabase-index-in-rangeIncorporated into unique caller. 1.24defsubstdatabase-normalize-indexMake INDEX be in the range 1 to (database-no-of-records database).Incorporated into unique caller. 1.24defsubstdatabase-unnamed-pIncorporated into unique caller. 1.24defsubstdate->weekday-abbrevIncorporated into unique caller. 1.24defsubstdb-if-file-readable-pReturn FILENAME if the file is readable, nil otherwise.Converted callers to use `locate-file'. 1.24defsubstdb-x-jump-to-pointMove to the field or record nearest the mouse position. See `db-jump-to-point' for more details.Was for Emacs 18 support. Also deleted: associated keybindings. 1.24defsubstdbf-set-this-field-indexIncorporated into unique caller. 1.24defsubstdbf-this-record-fieldReturn the value of the field with name FIELDNAME from `dbf-this-record'. You may want to use `dbf-displayed-record-field' instead.Unused. 1.24defsubstdisplay-current-recordUnused. 1.24defsubstdisplayspec-set-reachableUnused. 1.24defsubstinteger->monthabbrevIncorporated into unique caller. 1.24defsubstinteger->monthnameIncorporated into callers. 1.24defsubstinteger->weekdayIncorporated into unique caller. 1.24defsubstmonthname->integerIncorporated into unique caller. 1.24defsubstopspectinfo-param-nameUnused. 1.24defsubstoptspecinfo-param->valueIncorporated into unique caller. 1.24defsubstoptspecinfo-settorIncorporated into unique caller. 1.24defunbyte-compile-databaseCompile source (.el) files in EDB, the Emacs database, which need it. If optional prefix argument ALL is non-nil, every source file is recompiled. You are likely to want unconditional recompilation if you have tried to compile any of the files by hand and want to replace the (possibly incorrect) results.Incorporated into unique caller. 1.24defuncomma-delimited-string->listUnused. 1.24defundatabase-check-all-sepinfosIncorporated into unique caller. 1.24defundatabase-delete-linkIncorporated into unique caller. 1.24defundatabase-delete-record-at-indexUnused. 1.24defundatabase-no-identical-keys-pReturn t if no two elements of DATABASE have the same ordering keys, or if user says to proceed even though identical keys have been found. DATABASE should be ordered when this is called. Optional argument ORDERER is used as the ordering function.Unused. 1.24defundatabase-set-modified-p-internalUnused. 1.24defundatabase-set-temp-delimitersUnused. 1.24defundatabase-stored->actual-internalDo the real work of `database-stored->actual'.Incorporated into unique caller. 1.24defundate-month-day-compatibleIncorporated into unique caller. 1.24defundate-order-within-yearIncorporated into unique caller. 1.24defundate-year-shortIncorporated into unique caller. 1.24defundb-buffer-substituteMake replacements in the current buffer according to SUBSTITUTIONS. SUBSTITUTIONS is list of pairs of strings; the cdr of each pair will be substituted for the car, in order, unless optional argument BACKWARD is non-nil, in which case the car is substituted for the cdr and the substitutions are done in reverse order. If optional third argument CHECK is non-nil, the user is warned if any of the substituted-in strings already appears in the buffer; such a situation would make substitution, then unsubstitution, not yield a result identical to the original buffer, since all instances of the substituted-in string will be assumed on the reverse substitution to have been the result of replacing a substituted-for string. Return nil if CHECK is nil or there were no ambiguities; otherwise return a list of replacements creating ambiguity."Incorporated into unique caller. 1.24defundb-buryBury the data display and summary buffers. Spare either or both of these buffers by specifying optional arguments NOT-DATA-DISPLAY and NOT-SUMMARY.Incorporated into unique caller. 1.24defundb-canonicalize-creation-methodsIncorporated into unique caller. 1.24defundb-choose-valueIncorporated into unique caller. 1.24defundb-count-arrayReturn the number of times that ITEM appears in ARRAY; test with `equal'.Converted callers to use `db-count-newlines'. 1.24defundb-create-summary-bufferIncorporated into unique caller. 1.24defundb-ds-displayedIncorporated into unique caller. 1.24defundb-enum-do-completionsGiven a string INPUT-REP and an enum TYPE, return INPUT-REP if it is a valid input representation, otherwise see if it completes to a valid one, and show the possible completions.Incorporated into unique caller. 1.24defundb-enum-make-actual->displayReturn a function appropriate for a displayspec's actual->display slot.Incorporated into unique caller. 1.24defundb-enum-make-actual->storedReturn nil or a function appropriate for a displayspec's actual->stored slot.Incorporated into unique caller. 1.24defundb-enum-make-display->actualReturn a function appropriate for a displayspec's display->actual slot. The input string is converted into one of the alternatives of TYPE, and if ambiguities exist, they are resolved interactively.Incorporated into unique caller. 1.24defundb-enum-make-help-infoReturn a string listing the input representations of TYPE.Incorporated into unique caller. 1.24defundb-enum-process-alternativesTake an alternatives list of the form accepted by `define-enum-type'. Return a list of three alists appropriate for use by display->actual, actual->display, and actual->stored (also stored->actual) functions.Incorporated into unique caller. 1.24defundb-filename-sans-extensionConverted callers to use `file-name-sans-extension'. 1.24defundb-fontifyFontify the region between START and END. Leave out the leading and trailing white space.Unused. Fontification and such will probably return later. 1.24defundb-hide-recordsUnused. 1.24defundb-locate-file-on-pathReturn the full path of a file named FILENAME located in the current directory or on PATH, which is a list of directories (strings) or nil for the current directory.Converted callers to use `locate-file'. 1.24defundb-locate-file-with-extensionsReturn the name of a readable file starting with FILENAME or FILENAME's basename and ending with a string in EXTENSIONS, which is a list. EXTENSIONS may be nil, in which case FILENAME is searched for as is.Converted callers to use `locate-file'. 1.24defundb-locate-file-with-extensions-on-pathReturn the name of a readable file starting with FILENAME or FILENAME's basename and ending with a string in EXTENSIONS, which is a list. PATH is a list of strings representing directories to be searched in order after the current one; they may be relative directories. Nil means the current directory.Converted callers to use `locate-file'. 1.24defundb-logPostpend STRING to buffer *Database-Log*.Incorporated into unique caller. 1.24defundb-merge-internalReturn a third database.Incorporated into unique caller. 1.24defundb-operate-on-local-variablesApply REGION-FUNCTION to the local-variables region of the buffer. Return t if a local-variables region was found; REGION-FUNCTION should act by side effect.Incorporated into unique caller. 1.24defundb-parse-match-objectIncorporated into unique caller. 1.24defundb-prepare-to-debugPrepare to debug EDB. Set variables `debug-on-error', `db-disable-debugging-support', and `db-debug-p'. Also load uncompiled EDB source.Dropped special debugging support altogether. 1.24defundb-print-match-objectIncorporated into unique caller. 1.24defundb-rdb-format-to-typeGiven FORMAT from an RDB field definition, return an EDB record field TYPE.Incorporated into unique caller. 1.24defundb-rdb-lookup-fieldLookup FIELD-TAG in the RDB database field list, returning its associated NAME (a symbol).Incorporated into unique caller. 1.24defundb-rdb-read-list-field-defsPositioned at the blank line preceeding the field definitions in an RDB List file, read the field definitions and return them as an association list: ((FIELD-NAME FIELD-DEF FIELD-HELP)...).Incorporated into unique caller. 1.24defundb-rdb-read-table-field-defsPositioned at the field name line in an RDB Table file, read the field definitions and setup EDB for regular-file format. Leave the buffer positioned before the first record, if any.Incorporated into unique caller. 1.24defundb-rdb-setup-internalInternal function to do the real work of `db-rdb-setup', without certain safety checks. This function should only be called once per database. Argument is the FIELD-SPECS (see db-rdb-setup).Incorporated into unique caller. 1.24defundb-read-fieldvalue-from-minibufferIncorporated into unique caller. 1.24defundb-save-database-no-bufferIncorporated into unique caller. 1.24defundb-set-auto-edit-modeSet `db-auto-edit-mode' to ARG.Unused. 1.24defundb-set-field-helpInstall a help string for a given field. Construct a new type by copying the current one, changing help string, and installing the new type.Unused. This will return later in some form or another. 1.24defundb-set-field-variablesIncorporated into unique caller. 1.24defundb-string-replace-regexp-2Converted unique caller to use `replace-regexp-in-string'. 1.24defundb-string-substituteSubstitute NEWCHAR for instances of OLDCHAR in STRING. NEWCHAR and OLDCHAR are characters.Converted unique caller to use `subst-char-in-string'. 1.24defundb-string-substitute-optConverted unique caller to use `subst-char-in-string'. 1.24defundb-string-substitute-substring-general-caseConverted callers to use `replace-regexp-in-string'. 1.24defundb-tagged-lookup-fieldIncorporated into unique caller. 1.24defundb-tagged-setup-internalDo the real work of `db-tagged-setup'. This function should only be called once per database.Incorporated into unique caller. 1.24defundb-this-bufferRun EDB on the file corresponding to the current buffer. The current buffer is killed first.Unused. 1.24defundb-toggle-auto-edit-modeChange whether cursor movement in view mode causes edit mode to be entered. See variable `db-auto-edit-mode'. With a nonzero prefix argument, set db-auto-edit-mode to t. With a zero prefix argument, set db-auto-edit-mode to nil.Unused. 1.24defundbf-check-if-before-fieldIncorporated into unique caller. 1.24defundbf-check-if-beyond-fieldIncorporated into unique caller. 1.24defundbf-format-name->specReturn a format file specifier (a list of values for format variables).Unused. 1.24defundbf-goto-fieldUnused. 1.24defundbf-in-indentation-pIncorporated into unique caller. 1.24defundbf-install-format-file-specIncorporated into unique caller. 1.24defundbf-install-format-name-and-specUnused. 1.24defundbf-install-format-specIncorporated into unique caller. 1.24defundbf-kill-summaryKill this data display buffer's associated database summary buffer.Incorporated into unique caller. 1.24defundbf-make-format-file-specIncorporated into unique caller. 1.24defundbf-process-fieldIncorporated into unique caller. 1.24defundbf-set-buffer-local-variablesIncorporated into unique caller. 1.24defundbf-set-field-textUnused. 1.24defundbf-summarize-linkUnused. 1.24defundbf-this-field-text-unrectIncorporated into unique caller. 1.24defundbf-this-record-set-field-and-redisplaySet field with name FIELDNAME in `dbf-this-record' to VALUE. Causes the entire record to be redisplayed immediately. You may want to use `dbf-displayed-record-set-field-and-redisplay' instead.Unused. Also deleted: associated `make-obsolete' form. 1.24defundef-date-disptype???Converted callers to use `define-displaytype-from-displayspec' directly. 1.24defundef-time-disptype???Converted callers to use `define-displaytype-from-displayspec' directly. 1.24defunformat-spec-format-fileIncorporated into unique caller. 1.24defuninteger->weekday-abbrevUnused. 1.24defunload-databaseLoad all the files of EDB, the Emacs database. With prefix argument, load source, not compiled, code; run EDB interpreted.Incorporated into unique caller. 1.24defunload-db-aux-fileIncorporated into unique caller. 1.24defunmake-default-recordIncorporated into unique caller. 1.24defunmake-enum-member-ordererReturn an ordering function for the enum type TYPE.Incorporated into unique caller. 1.24defunmake-enum-member-orderer-internalGiven an enum type TYPE, create an ordering function which compares two items in the enum type's alternatives list. The resulting function returns LESS-VALUE if its first argument precedes its second argument in the alternative list, EQUAL-VALUE if they're equal or neither appears, and GREATER-VALUE if the first follows the second. If one of the arguments doesn't appear in the alternatives list, the other is considered to precede it.Incorporated into unique caller. 1.24defunmake-enum-member-sorterReturn a sorting function for the enum type TYPE.Incorporated into unique caller. 1.24defunmake-format-printerIncorporated into unique caller. 1.24defunmake-linkUnused. Also deleted: associated `make-obsolete' form. 1.24defunmake-similar-databaseReturn a database similar to ORIGINAL.Incorporated into unique caller. 1.24defunmap-data-display-buffersApply FUNCTION to each data display buffer of DATABASE.Incorporated into unique caller. 1.24defunordinary-truncation-functionIncorporated into unique caller. 1.24defunprint-compare-recordsIncorporated into unique caller. 1.24defunprint-databaseUnused. 1.24defunprint-recordIncorporated into unique caller. 1.24defunread-sep-itemsUnused. 1.24defunrecord-sep-lines-functionUnused. 1.24defunrecordfieldspecs-compatibleReturn t if the databases' recordfieldspecs have the same types.Incorporated into unique caller. 1.24defunrecordfieldtype-pConverted unique caller to consult hash table directly. 1.24defunreturn-right-justify-padding-functionUnused. 1.24defunright-justify-padding-functionUnused. 1.24defunright-justify-slotsetter-functionIncorporated into unique caller. 1.24defunSFf-isbn-check-sumFrom _Numbers, Groups and Codes_ by J.F. Humphreys and M. Y. Prest, Cambridge University Press, Avon: 1989. page 233. Example: A well-known example of error-correction is provided by the ISBN (International Standard Book Number) of published books. This is a sequence of nine digits a1a2...a9, where each ai is one of the numbers 0,1,...,9, together with a check digit which is one of the symbols 0,1,2,3,4,5,6,7,8,9, or X (with X representing 10). This last digit is included so as to give a check that the previous 9 digits have been correctly transcribed, and is calculated as follows. Form the integer 10a1 + 9a2 + 8a3 +... +2a9 and reduce this modulo 11 to obtain an integer b between 1 and 11 inclusive. The check digit is obtained by subtracting b from 11.Incorporated into unique caller. 1.24defunstring-is-yn-pUnused. 1.24defunstring-or-nil->number-or-nilIncorporated into unique caller. 1.24defunstring-to-number-trimThis was to support a bug in Emacs 19.28 whereby `isfloat_string' failed when its argument had trailing spaces, so that (string-to-number "5.4") => 5.4 (correct) but (string-to-number "5.4 ") => 5 (incorrect).Callers were moved into a new test/choice scope evaluated at load-time, and changed to use the correct variant. 1.24defunupdate-displayspec-from-optspec-and-valueIncorporated into unique caller. 1.24defunwrite-sep-itemsUnused. 1.24defunzero-or-empty-date-pIncorporated into unique caller. 1.24defvaractual->display-error-string""String displayed when the actual->display function doesn't return a string.Incorporated value as-is. 1.24defvarcountry-list'("Canada" "Israel" "Switzerland" "Japan" "West Germany" "United States" "Zambia")List of country names. Far from complete.This kind of information may return later as part of some type library (edb-t-FOO.el file). 1.24defvardatabase-mode-line-formatIncorporated value as-is. 1.24defvardb-auto-edit-modetnil if movement around the data display buffer is permitted in view mode. When this variable is non-nil (it defaults to t), mousing and most movement commands cause edit mode to be entered on the appropriate field. Don't set this variable directly; use command `db-toggle-auto-edit-mode'.Unused. 1.24defvardb-debug-pnil*Non-nil if database debugging is enabled. Defaults to nil. Has no effect on code compiled with `db-disable-debugging-support' set.Dropped special debugging support altogether. 1.24defvardb-delete-record-modifies-database-ptNon-nil if deleting a record should mark the database as modified.Incorporated value as-is. 1.24defvardb-disable-debugging-supporttIf non-nil, then debugging calls will be compiled out of the source and the variable `db-debug-p' will have no effect. Setting this variable at run-time has no effect if you are running EDB compiled; you must set it when you compile EDB, or run EDB interpreted. Defaults to t.Dropped special debugging support altogether. 1.24defvardb-filename-extension-regexp"[^.]\\(\\.\\([-a-z]*\\)\\)$"Submatch 1 is the extension with leading period; submatch 2 is without.Unused. 1.24defvardb-fontificationdb-running-lucid-emacsNon-nil if uneditable text in data display buffers should use a special font. Don't set this unless you are running Lucid GNU Emacs!Fontification and such will probably return later. 1.24defvardb-mouse-buffer-switch-moves-point-pUnused. 1.24defvardb-running-lucid-emacs(string-match "Lucid" emacs-version)Converted refs to check the property `edb-running-lemacs' of symbol `emacs-version'. 1.24defvardb-running-lucid-emacs(string-match "Lucid" emacs-version)Support for Lucid Emacs moved to db-lemacs.el. 1.24defvardb-use-completing-readt*Non-nil if EDB should use `completing-read' when reading enumerated types. Otherwise, on erroneous enumeration input, EDB shows the possible completions but doesn't correct the input.Incorporated value as-is. 1.24defvardbf-fieldabbrevsnilDatabase-format-specific alist of fieldabbrevs and displayspecs.Incorporated value as-is. 1.24defvardbm-<-prefix"^<"Incorporated value as-is. 1.24defvardbm-=-prefix"^="Incorporated value as-is. 1.24defvardbm->-prefix"^>"Incorporated value as-is. 1.24defvardbm-and-connective"[ \t]+and[ \t]+"Incorporated value as-is. 1.24defvardbm-not-prefix"^[ \t]*not[ \t]+"Incorporated value as-is. 1.24defvardbm-or-connective"[ \t]+or[ \t]+"Incorporated value as-is. 1.24defvaredb-directorynilA string, the name of the directory containing the EDB source files.Converted unique caller to use default directory. 1.24defvarmapfields-fieldnilThe current field value in a call to `mapfields-macro'.Dropped support for mapping over fields. 1.24defvarmapfields-indexnilThe current field index in a call to `mapfields' or `mapfields-macro'.Dropped support for mapping over fields. 1.24defvarmode-motion-hooknilUnused. Perhaps for Lucid Emacs support? 1.24defvarspace-maybe-regexp-limit8Emacs 19's regexp routines fix bugs in the Emacs 18 and Lucid Emacs versions, but are sometimes much slower. For deeply indented fields, this can result in very slow editing. We disable some error-checking and correction (which oughtn't ever be invoked anyway) for fields indented more than `space-maybe-regexp-limit' characters. Eventually EDB will use a completely different approach to indented fields.Incorporated value as-is. 1.24defvaruse-electric-help-pnil*Non-nil if Emacs programs should use electric help where possible. Don't set this to a non-nil value unless the ehelp package is available.Unused. 1.24fsetdb-warndb-warningUnused. 1.24fsetdefine-displaytype-aliasdefine-displaytype-from-displayspecThis was also marked with `make-obsolete'. 1.24fsetdefine-recordfieldtype-aliasdefine-recordfieldtype-from-recordfieldspecThis was also marked with `make-obsolete'. 1.23deflocalvardb-default-field-type'stringThe type to use for record fields whose type is not explicitly specified.Incorporated value as-is. Converted type system machinery to default to `string' automatically. 1.23deflocalvardbf-displayspec-begin-markersnilAn array of markers, one for the beginning of each field of the display format.Unused. 1.23defmacroin-buffer-simpleExecute, in BUFFER, forms of BODY. BODY shouldn't move point in a buffer displayed in a non-selected window.Converted callers to use `with-current-buffer'. Also deleted: attendant `put' forms. 1.23defmacroin-windowExecute, in WINDOW, forms of BODY. This is more useful than `in-buffer' for window manipulation, as by `scroll-up'.Converted callers to use `with-selected-window'. Also deleted: attendant `put' forms. 1.23defmacromake-optspecinfoargs: PARAM-NAME SETTOR-OR-ACCESSOR VALUE-FN. SETTOR-OR-ACCESSOR is either a settor function, a slotname, or a list of slotnames. In the latter two cases, it's first converted into a settor.Incorporated into unique caller. 1.23defsubstdatabase-last-linkIncorporated into unique caller. 1.23defsubstdatabase-linkReturn the link of DATABASE at index N. The first link is numbered 1.Converted unique caller to use `next-link-and-index' directly. 1.23defsubstdatabase-link-and-indexReturn a cons of (link . index) for the link of DATABASE with index N. If HIDEP is non-nil, then hidden links are skipped. If MARKEDP is non-nil, only marked links count. This shouldn't be used for going to fixed points in the database (like the last record), both because hiding may change its semantics and because, in that case, just using `(link-prev (database-first-link database))' and `(database-no-of-records database)' is more efficient.Converted unique caller to use `next-link-and-index' directly. 1.23defsubstdb-functionpReturn t if OBJECT is a function (is funcallable), nil otherwise.Converted callers to use `functionp'. 1.23defunbob-visible-pConverted unique caller to use `window-start' and `point-min'. 1.23defundatabase-buffer-pT if this buffer is a database data display buffer or database summary buffer.Incorporated into unique caller. 1.23defundatabase-list-of-linksIncorporated into unique caller. 1.23defundatabase-set-modified-p-internalUnused. 1.23defundb-file-resolve-symlinkReturn the non-link FILE eventually points to, or FILE if it's not a symbolic link. This gets in an infinite loop if FILE points into a circular list of symlinks.Converted unique caller to use `file-chase-links'. 1.23defundb-insertConspirator in the bletcherous `insert' override. 1.23defundb-insert-file-contentsIncorporated into unique caller. 1.23defundb-match-stringReturn the string matched by parentheses number N. If there is a SOURCE string, return the substring of that string; else, return substring of the current buffer.Converted callers to use `match-string'. 1.23defundb-match-string-maybeLike `db-match-string', but return nil if there was no match for parenthesis N.Converted callers to use `match-string'. 1.23defundb-rassocReturn non-nil if ELT is the cdr of an element of LIST. Comparison done with `equal'. The value is actually the element of LIST whose cdr is ELT.Converted callers to use `rassoc'. 1.23defundb-set-fieldname-varsSet variables and slots of DATABASE that can be set from optional argument FIELDNAMES-LIST or, if it is nil, from the fieldnames slot of the database.Incorporated into unique caller. 1.23defundb-symbol-appendUnused. 1.23defundbc-compute-indexIncorporated into unique caller. 1.23defunedb-updateInstall the EDB update found in the current buffer after point. EDB is assumed to be in the directory specified by `edb-directory'. (If that variable is not set, the user is prompted for the location of the files.) If you have trouble with this command, it is likely that your version of EDB is not exactly the same as the last release. You might have an old release, or you might have a pre-release.No longer relevant; EDB is no longer distributed via patches. 1.23defuneob-visible-pConverted unique caller to use `window-end' and `point-max'. 1.23defunfirstnReturn a copy of the first N elements of LIST.Converted unique caller to use `subseq'. 1.23defunindentify-absoluteUnused? 1.23defunmake-summary-indentationUnused. 1.23defunmake-summary-initial-indentationUnused. 1.23defunorder->sortGiven an ORDER function, return a sort function.Incorporated into unique caller. 1.23defunrecord->link-and-indexReturn a list `(link index)' for the link containing RECORD in DATABASE. Return nil if there is no such link.Unused. 1.23defunsort->orderGiven a SORT function, return an order function.Incorporated into unique caller. 1.23defvardb-loggednilT if logging has been done recently (since the user was last shown the log).Unused. Unique set site deleted. 1.23fsetdb-old-insertinsertOriginal value of `insert' before override.This practice is dangerous because it has a high probability of breaking other code. The call sites were converted to use `insert' directly. 1.23fsetdb-old-save-some-bufferssave-some-buffersOriginal value of `save-some-buffers' before override.This practice is dangerous because it has a high probability of breaking other code. The call site was converted to use `save-some-buffers' directly, anyway. 1.23funcdb-insert-funcarg: STRING-OR-CHARConspirator in the bletcherous `insert' override.edb-1.31/skram/retired.edb0000444000175000017500000000223610745370012013613 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "RETIRED!" :fields [since kind thing default-value documentation comments] :field-separator "\C-a" :record-separator "\f" :summary-format "\\since,width=5 \\kind,width=12 \\thing" :display t \thing (\kind\ ) \default-value \since --------------------------- \comments --------------------------- \documentation :EOTB ;;; retired.edb ends here edb-1.31/skram/skram.edb0000444000175000017500000000250710745370012013273 0ustar ttnttn:EDB (single) ;;; -*- emacs-lisp -*- ;; Copyright (C) 2005,2006,2007,2008 Thien-Thi Nguyen ;; ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. :name "SKRAM" :fields [thing kind thumbs-one thumbs-two places] :field-separator "\n:" :record-terminator "\n\n" :summary-format "\\thumbs-one,width=6 \\kind,width=10 \\thing" :display t Self-Knowledge Requires Attentive Maintenance! ============================================= Apparently, `\thing\ ' can be found in various places in the source: \places (\kind here) Prospects for its continued survival in EDB 1.x: \thumbs-one As for EDB 2.x, for now we'll just say "\thumbs-two\ ". :EOTB ;;; skram.edb ends here edb-1.31/skram/skram.fmt0000444000175000017500000000147110745370012013326 0ustar ttnttnSelf-Knowledge Requires Attentive Maintenance! ============================================= Apparently, `\thing\ ' can be found in various places in the source: \places (\kind here) Prospects for its continued survival in EDB 1.x: \thumbs-one As for EDB 2.x, for now we'll just say "\thumbs-two\ ". Local Variables: eval: (database-set-fieldnames-to-list db '(thing kind thumbs-one thumbs-two places)) eval: (let* ((db database) (fsep (database-field-sepinfo db)) (rsep (database-record-sepinfo db))) (setf (database-print-name db) "SKRAM" (sepinfo-sep-string fsep) "\n:" (sepinfo-sep-string rsep) "\n\n" (sepinfo-post-last-string rsep) "\n\n")) eval: (dbf-set-summary-format "\\thumbs-one,width=6 \\kind,width=10 \\thing") End: edb-1.31/tests/0000755000175000017500000000000011016452347011531 5ustar ttnttnedb-1.31/tests/ChangeLog0000444000175000017500000000642011016242100013263 0ustar ttnttn2008-05-25 Thien-Thi Nguyen When deleting a record, clear highest (post-shift) vov element. * b00.test: Display vov before and after; add check for highest index cleared; use `error'. (vov): New func. 2008-05-24 Thien-Thi Nguyen Use GNUmakefile throughout. * GNUmakefile.in: Rename from Makefile.in. (BLARGH): Convert assignment to appending assignment `TESTS +='. 2008-05-24 Thien-Thi Nguyen Fix OBOE: When deleting a record, limit shift-in count properly. * b00.test: New file. * Makefile.in (BLARGH): Add b00.test. 2008-05-24 Thien-Thi Nguyen Add support for testing regressions using "make check". * Makefile.in (BLARGH): New var. (check-TESTS): Also check tests listed in $(BLARGH). 2008-05-24 Thien-Thi Nguyen Update `load-path' in ebatch for testing. * ebatch.in (topdir): Delete var. (loadfrom): New var; use it to add to `load-path'. 2007-04-24 Thien-Thi Nguyen * null.test: New file. * Makefile.in (TESTS): Add null.test. 2007-04-24 Thien-Thi Nguyen * Makefile.in (check-TESTS): No longer discard stdout and stderr. * ebatch.in: Discard output, but only if env var DEBUG not set. 2006-01-17 Thien-Thi Nguyen * Makefile.in (EMACS): Use configure-substituted var `EMACS'. 2006-01-03 Thien-Thi Nguyen * Makefile.in (emacs): Delete var. (EMACS): New var. (TESTENV): Add `EMACS' and its value. * ebatch.in (emacs): Use env var `EMACS'. 2005-01-19 Thien-Thi Nguyen * Makefile.in (topsrcdir): New var. (TESTSENV): Add `srcdir' and `topsrcdir'. (check-TESTS): Spell TESTSENV correctly. * skram.test: Use env var `topsrcdir'. * isbn.test: Use env var `srcdir'. 2005-01-19 Thien-Thi Nguyen * Makefile.in (srcdir): New var. (check-TESTS): Use it. * ebatch.in: Use @abs_top_srcdir@. 2005-01-18 Thien-Thi Nguyen * skram.test: Use `error' instead of `kill-emacs'. 2005-01-18 Thien-Thi Nguyen * isbn.test: New file. * Makefile.in (topdir): Delete var. (ebatch): Likewise. (wily-emacs): Likewise. (check): Remove check-isbns. (TESTS): Add isbn.test. (check-isbns): Delete target. 2005-01-18 Thien-Thi Nguyen * skram.test: New file. * Makefile.in (check): Remove check-skram. (TESTSENV): New var. (TESTS): Add skram.test. (check-TESTS): Use $(TESTENV). (check-skram): Delete target. 2005-01-18 Thien-Thi Nguyen * friendly.test: New file. * Makefile.in (TESTS): Add friendly.test. 2005-01-18 Thien-Thi Nguyen * ebatch.in: New file. * alive.test: Use file "./ebatch". 2005-01-18 Thien-Thi Nguyen * alive.test: New file. * Makefile.in (check): Depend on check-TESTS. (TESTS): New var. (check-TESTS): New target. 2004-09-12 Thien-Thi Nguyen * check-isbns.el: New file. * Makefile.in (emacs): New var. (topdir): Likewise. (ebatch) LIkewise. (wily-emacs): Likewise. (check): Remove actions. Depend on `check-skram' and `check-isbns'. (check-skram): New target. (check-isbns): Likewise. 2004-09-11 Thien-Thi Nguyen * Makefile.in: New file. edb-1.31/tests/GNUmakefile.in0000444000175000017500000000303411016047446014206 0ustar ttnttn# GNUmakefile # Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen # # This file is part of EDB. # # EDB 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 3, or (at your option) any later # version. # # EDB 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 EDB; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. srcdir = @srcdir@ topsrcdir = @abs_top_srcdir@ EMACS = @EMACS@ all: @echo '(nothing to be done for "$@")' check: check-TESTS TESTSENV = \ MAKE="$(MAKE)" \ srcdir="$(srcdir)" \ topsrcdir="$(topsrcdir)" \ EMACS="$(EMACS)" TESTS = alive.test null.test friendly.test skram.test isbn.test # regressions, sigh TESTS += b00.test check-TESTS: @all=0; ok=0 ; \ for prog in $(TESTS) ; do \ all=`expr 1 + $$all` ; \ if $(TESTSENV) $(srcdir)/$$prog ; \ then echo PASS: $$prog ; ok=`expr 1 + $$ok` ; \ else echo FAIL: $$prog ; fi ; \ done ; \ if [ $$all = $$ok ] ; \ then echo All $$all tests passed. ; \ else echo `expr $$all - $$ok` of $$all tests failed. ; \ false ; \ fi # GNUmakefile ends here edb-1.31/tests/alive.test0000555000175000017500000000007410745370012013530 0ustar ttnttn":"; exec ./ebatch --no-site-file -l $0 (require 'database) edb-1.31/tests/b00.test0000555000175000017500000000115211016242247013007 0ustar ttnttn":"; exec ./ebatch --no-site-file -l $0 (require 'database) (edb-interact (expand-file-name "examples/null.edb" (getenv "topsrcdir")) nil) (defun vov () (edb--1D dbc-database :vov)) (defun count () (database-no-of-records dbc-database)) (let ((vsz (length (vov))) (n (count))) (unless (<= vsz n) (db-copy-record (- vsz n)) (setq n (count))) (message "before[%d]:" (count)) (pp (vov)) (db-delete-record t) (message "after[%d]:" (count)) (pp (vov)) (unless (= (1- n) (count)) (error "ERROR: delete failed")) (when (aref (vov) (count)) (error "ERROR: unclean shift (highest non-nil)"))) edb-1.31/tests/check-isbns.el0000444000175000017500000005021610745370012014242 0ustar ttnttn;;; check-isbns.el --- part of EDB, the Emacs database ;; Copyright (C) 2004,2005,2006,2007,2008 Thien-Thi Nguyen ;; Author: Bertrand Petit ;; Michael Ernst ;; This file is part of EDB. ;; ;; EDB 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 3, or (at your option) any later ;; version. ;; ;; EDB 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 EDB; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ;; MA 02110-1301, USA. ;;; Commentary: ;; Test cases for the ISBN type for EDB. ;; To run the tests, load this file, then do M-x check-isbns RET. ;;; Code: (require 'db-isbn) (eval-when-compile (require 'cl)) (defun check-isbns () (interactive) (dolist (isbn succeeding-isbns) (db-isbn-constraint isbn nil nil nil)) (dolist (isbn failing-isbns) (let ((failed nil)) (condition-case nil (db-isbn-constraint isbn nil nil nil) (error (setq failed t))) (unless failed (error "isbn-constraint didn't fail on %s" isbn)))) (message "ISBN check successful.")) (defvar succeeding-isbns '("0-14-012950-2" "0-330-24024-2" "0-345-34787-0" "0-345-37077-5" "0-380-50773-0" "0-441-27233-9" "0-553-28368-5" "0-553-29817-8" "0-575-04689-9" "0-586-20764-3" "0-586-21292-2" "0-812-52458-6" "0-8600-7901-5" "2-03-037003-7" "2-07-036822-X" "2-08-070320-X" "2-08-070330-7" "2-13-037888-9" "2-2011-0152-3" "2-207-22942-4" "2-207-22958-0" "2-207-30002-1" "2-207-30008-0" "2-207-30009-9" "2-207-30017-X" "2-207-30021-8" "2-207-30025-0" "2-207-30026-9" "2-207-30029-3" "2-207-30036-6" "2-207-30037-4" "2-207-30038-2" "2-207-30043-9" "2-207-30051-X" "2-207-30065-X" "2-207-30083-8" "2-207-30087-0" "2-207-30110-9" "2-207-30120-6" "2-207-30134-6" "2-207-30142-7" "2-207-30142-7" "2-207-30143-5" "2-207-30165-6" "2-207-30166-4" "2-207-30175-3" "2-207-30191-5" "2-207-30268-7" "2-207-30276-8" "2-207-30314-4" "2-207-30333-0" "2-207-30334-9" "2-207-30336-5" "2-207-30338-1" "2-207-30339-X" "2-207-30344-6" "2-207-30345-4" "2-207-30346-2" "2-207-30347-0" "2-207-30348-9" "2-207-30349-7" "2-207-30350-0" "2-207-30351-9" "2-207-30352-7" "2-207-30353-5" "2-207-30354-3" "2-207-30356-X" "2-207-30358-6" "2-207-30361-6" "2-207-30362-4" "2-207-30363-2" "2-207-30365-9" "2-207-30366-7" "2-207-30368-3" "2-207-30369-1" "2-207-30369-1" "2-207-30370-5" "2-207-30372-1" "2-207-30373-X" "2-207-30375-6" "2-207-30376-4" "2-207-30377-2" "2-207-30378-0" "2-207-30379-9" "2-207-30381-0" "2-207-30383-7" "2-207-30385-3" "2-207-30386-1" "2-207-30387-X" "2-207-30387-X" "2-207-30388-8" "2-207-30389-6" "2-207-30390-X" "2-207-30391-8" "2-207-30392-6" "2-207-30393-4" "2-207-30394-2" "2-207-30396-9" "2-207-30397-7" "2-207-30398-5" "2-207-30400-0" "2-207-30401-9" "2-207-30402-7" "2-207-30403-5" "2-207-30405-1" "2-207-30406-X" "2-207-30408-6" "2-207-30411-6" "2-207-30412-4" "2-207-30416-7" "2-207-30417-5" "2-207-30418-3" "2-207-30419-1" "2-207-30420-5" "2-207-30421-3" "2-207-30423-X" "2-207-30424-8" "2-207-30425-6" "2-207-30426-4" "2-207-30427-2" "2-207-30428-0" "2-207-30429-9" "2-207-30430-2" "2-207-30431-0" "2-207-30432-9" "2-207-30433-7" "2-207-30434-5" "2-207-30435-3" "2-207-30436-1" "2-207-30437-X" "2-207-30438-8" "2-207-30439-6" "2-207-30440-X" "2-207-30441-8" "2-207-30442-6" "2-207-30444-2" "2-207-30445-0" "2-207-30446-9" "2-207-30447-7" "2-207-30448-5" "2-207-30449-3" "2-207-30450-7" "2-207-30451-5" "2-207-30452-3" "2-207-30453-1" "2-207-30454-X" "2-207-30455-8" "2-207-30456-6" "2-207-30456-6" "2-207-30458-2" "2-207-30459-0" "2-207-30460-4" "2-207-30474-4" "2-207-30564-3" "2-207-30565-1" "2-207-34001-5" "2-207-34001-5" "2-207-34002-3" "2-207-34002-3" "2-207-34003-1" "2-207-34004-X" "2-207-34004-X" "2-207-34005-8" "2-207-34005-8" "2-207-34006-6" "2-207-34006-6" "2-207-34007-4" "2-207-34007-4" "2-207-34009-0" "2-207-34009-0" "2-207-34010-4" "2-207-34011-2" "2-207-34011-2" "2-207-34012-0" "2-207-34012-0" "2-207-34014-7" "2-207-50015-2" "2-207-50057-8" "2-207-50090-X" "2-207-50265-1" "2-207-50266-X" "2-207-50330-5" "2-207-50409-3" "2-207-50545-6" "2-226-00362-2" "2-226-00364-9" "2-226-00406-8" "2-226-00464-5" "2-226-00465-3" "2-226-00467-X" "2-226-00573-0" "2-226-00574-9" "2-226-00628-1" "2-226-00629-X" "2-226-00630-3" "2-226-00631-1" "2-226-00721-0" "2-226-00722-9" "2-226-00732-6" "2-226-00818-7" "2-226-00819-5" "2-226-00820-9" "2-226-01142-0" "2-226-01198-6" "2-226-01562-0" "2-226-01692-9" "2-226-01772-0" "2-253-00060-4" "2-253-00608-4" "2-253-00609-2" "2-253-00723-4" "2-253-01378-1" "2-253-01554-7" "2-253-01555-5" "2-253-01556-3" "2-253-01572-5" "2-253-01866-X" "2-253-02039-7" "2-253-02142-3" "2-253-02208-X" "2-253-02209-8" "2-253-02307-8" "2-253-02309-4" "2-253-02310-8" "2-253-02310-8" "2-253-02578-X" "2-253-02580-1" "2-253-02626-3" "2-253-03150-X" "2-253-03151-8" "2-253-03152-6" "2-253-03341-3" "2-253-03411-8" "2-253-03428-2" "2-253-03463-0" "2-253-03558-0" "2-253-03559-9" "2-253-03582-3" "2-253-03628-5" "2-253-03629-3" "2-253-03659-5" "2-253-03676-5" "2-253-03717-6" "2-253-03718-4" "2-253-03751-6" "2-253-03970-5" "2-253-04095-9" "2-253-04120-3" "2-253-04142-4" "2-253-04206-4" "2-253-04290-0" "2-253-04311-7" "2-253-04332-X" "2-253-04526-8" "2-253-04680-9" "2-253-04735-X" "2-253-04908-5" "2-253-05087-3" "2-253-05270-1" "2-253-05342-2" "2-253-05438-0" "2-253-05767-3" "2-258-01662-2" "2-259-00042-8" "2-259-00043-6" "2-259-00104-1" "2-259-00105-X" "2-259-00168-8" "2-259-00205-6" "2-259-00247-1" "2-259-00288-9" "2-259-00312-5" "2-259-00338-9" "2-259-00376-1" "2-259-00393-1" "2-259-00424-5" "2-259-00448-2" "2-259-00510-1" "2-259-00511-X" "2-259-00513-6" "2-259-00532-2" "2-259-00566-7" "2-259-00581-0" "2-259-00603-5" "2-259-00616-7" "2-259-00627-2" "2-259-00639-6" "2-259-00685-X" "2-259-00695-7" "2-259-00732-5" "2-259-00778-3" "2-259-00809-7" "2-259-00859-3" "2-259-00874-7" "2-259-00877-1" "2-259-00895-X" "2-259-00905-0" "2-259-00926-3" "2-259-00935-2" "2-259-00953-0" "2-259-00958-1" "2-259-00962-X" "2-259-00974-3" "2-259-00988-3" "2-259-00998-0" "2-259-01006-7" "2-259-01042-3" "2-259-01049-0" "2-259-01066-0" "2-259-01080-6" "2-259-01082-2" "2-259-01091-1" "2-259-01095-4" "2-259-01102-0" "2-259-01144-6" "2-259-01165-9" "2-259-01179-9" "2-259-01185-3" "2-259-01196-9" "2-259-01205-1" "2-259-01223-X" "2-259-01239-6" "2-259-01251-5" "2-259-01298-1" "2-259-01304-X" "2-259-01335-X" "2-259-01341-4" "2-259-01346-5" "2-259-01351-1" "2-259-01378-3" "2-259-01386-4" "2-259-01390-2" "2-259-01397-X" "2-259-01459-3" "2-259-01469-0" "2-259-01472-0" "2-259-01491-7" "2-259-01492-5" "2-259-01501-8" "2-259-01517-4" "2-259-01556-5" "2-259-01560-3" "2-259-01561-1" "2-259-01572-7" "2-259-01586-7" "2-259-01590-5" "2-259-01596-4" "2-259-01597-2" "2-259-01597-2" "2-259-01600-6" "2-259-01626-X" "2-259-01627-8" "2-259-01667-7" "2-259-01676-6" "2-259-01680-4" "2-259-01808-4" "2-259-01813-0" "2-259-01816-5" "2-264-00441-X" "2-264-00912-8" "2-264-00913-6" "2-265-01113-4" "2-265-01164-9" "2-265-03701-X" "2-266-00261-9" "2-266-00288-0" "2-266-00289-9" "2-266-00327-5" "2-266-00328-3" "2-266-00335-6" "2-266-00348-8" "2-266-00350-X" "2-266-00384-4" "2-266-00425-5" "2-266-00431-X" "2-266-00443-3" "2-266-00444-1" "2-266-00455-7" "2-266-00456-5" "2-266-00465-4" "2-266-00490-5" "2-266-00495-6" "2-266-00496-4" "2-266-00505-7" "2-266-00515-4" "2-266-00539-1" "2-266-00540-5" "2-266-00565-0" "2-266-00571-5" "2-266-00591-X" "2-266-00597-9" "2-266-00606-1" "2-266-00628-2" "2-266-00643-6" "2-266-00646-0" "2-266-00667-3" "2-266-00716-5" "2-266-00756-4" "2-266-00761-0" "2-266-00780-7" "2-266-00793-9" "2-266-00794-7" "2-266-00794-7" "2-266-00817-X" "2-266-00818-8" "2-266-00822-6" "2-266-00843-9" "2-266-00843-9" "2-266-00844-7" "2-266-00845-5" "2-266-00878-1" "2-266-00879-X" "2-266-00886-2" "2-266-00887-0" "2-266-00888-9" "2-266-00896-X" "2-266-00904-4" "2-266-00906-0" "2-266-00912-5" "2-266-00923-0" "2-266-00924-9" "2-266-00933-8" "2-266-00935-4" "2-266-00945-1" "2-266-00955-9" "2-266-00957-5" "2-266-00983-4" "2-266-00995-8" "2-266-00995-8" "2-266-01001-8" "2-266-01027-1" "2-266-01046-8" "2-266-01050-6" "2-266-01051-4" "2-266-01056-5" "2-266-01072-7" "2-266-01072-7" "2-266-01073-5" "2-266-01073-5" "2-266-01079-4" "2-266-01089-1" "2-266-01091-3" "2-266-01093-X" "2-266-01095-6" "2-266-01106-5" "2-266-01107-3" "2-266-01112-X" "2-266-01124-3" "2-266-01129-4" "2-266-01130-8" "2-266-01130-8" "2-266-01138-3" "2-266-01150-2" "2-266-01151-0" "2-266-01159-6" "2-266-01174-X" "2-266-01174-X" "2-266-01176-6" "2-266-01177-4" "2-266-01185-5" "2-266-01186-3" "2-266-01194-4" "2-266-01202-9" "2-266-01202-9" "2-266-01210-X" "2-266-01210-X" "2-266-01217-7" "2-266-01221-5" "2-266-01226-6" "2-266-01229-0" "2-266-01235-5" "2-266-01239-8" "2-266-01254-1" "2-266-01261-4" "2-266-01268-1" "2-266-01269-X" "2-266-01276-2" "2-266-01277-0" "2-266-01278-9" "2-266-01292-4" "2-266-01293-2" "2-266-01303-3" "2-266-01304-1" "2-266-01305-X" "2-266-01314-9" "2-266-01315-7" "2-266-01341-6" "2-266-01346-7" "2-266-01354-8" "2-266-01354-8" "2-266-01359-9" "2-266-01360-2" "2-266-01365-3" "2-266-01392-0" "2-266-01400-5" "2-266-01403-X" "2-266-01408-0" "2-266-01417-X" "2-266-01423-4" "2-266-01434-X" "2-266-01435-8" "2-266-01445-5" "2-266-01457-9" "2-266-01479-X" "2-266-01483-8" "2-266-01490-0" "2-266-01491-9" "2-266-01491-9" "2-266-01499-4" "2-266-01506-0" "2-266-01510-9" "2-266-01520-6" "2-266-01530-3" "2-266-01582-6" "2-266-01582-6" "2-266-01594-X" "2-266-01595-8" "2-266-01602-4" "2-266-01603-2" "2-266-01614-8" "2-266-01615-6" "2-266-01616-4" "2-266-01650-4" "2-266-01656-3" "2-266-01664-4" "2-266-01669-5" "2-266-01669-5" "2-266-01670-9" "2-266-01680-6" "2-266-01681-4" "2-266-01694-6" "2-266-01695-4" "2-266-01696-2" "2-266-01734-9" "2-266-01736-5" "2-266-01747-0" "2-266-01752-7" "2-266-01758-6" "2-266-01759-4" "2-266-01761-6" "2-266-01772-1" "2-266-01773-X" "2-266-01797-7" "2-266-01798-5" "2-266-01799-3" "2-266-01834-5" "2-266-01835-3" "2-266-01836-1" "2-266-01850-7" "2-266-01851-5" "2-266-01870-1" "2-266-01870-1" "2-266-01872-8" "2-266-01893-0" "2-266-01894-9" "2-266-01917-1" "2-266-01918-X" "2-266-01919-8" "2-266-01935-X" "2-266-01936-8" "2-266-01944-9" "2-266-01954-6" "2-266-01955-4" "2-266-01956-2" "2-266-01976-7" "2-266-02001-3" "2-266-02038-2" "2-266-02039-0" "2-266-02040-4" "2-266-02041-2" "2-266-02042-0" "2-266-02068-4" "2-266-02069-2" "2-266-02080-3" "2-266-02097-8" "2-266-02098-6" "2-266-02116-8" "2-266-02117-6" "2-266-02118-4" "2-266-02138-9" "2-266-02138-9" "2-266-02139-7" "2-266-02177-X" "2-266-02279-2" "2-266-02280-6" "2-266-02292-X" "2-266-02303-9" "2-266-02325-X" "2-266-02357-8" "2-266-02767-0" "2-266-03513-4" "2-266-03697-1" "2-266-03742-0" "2-266-04039-1" "2-266-04982-8" "2-277-11061-2" "2-277-11369-7" "2-277-11424-3" "2-277-11439-1" "2-277-11463-4" "2-277-11484-7" "2-277-11495-2" "2-277-11496-0" "2-277-11515-0" "2-277-11529-0" "2-277-11533-9" "2-277-11542-8" "2-277-11552-5" "2-277-11562-2" "2-277-11568-1" "2-277-11574-6" "2-277-11589-4" "2-277-11595-9" "2-277-11613-0" "2-277-11618-1" "2-277-11633-5" "2-277-11657-2" "2-277-11707-2" "2-277-11712-9" "2-277-11721-8" "2-277-11722-6" "2-277-11723-4" "2-277-11724-2" "2-277-11752-8" "2-277-11767-6" "2-277-11768-4" "2-277-11774-9" "2-277-11778-1" "2-277-11779-X" "2-277-11799-4" "2-277-11813-3" "2-277-11814-1" "2-277-11821-4" "2-277-11829-X" "2-277-11830-3" "2-277-11836-2" "2-277-11847-8" "2-277-11870-2" "2-277-11879-6" "2-277-11886-9" "2-277-11903-2" "2-277-11909-1" "2-277-11910-5" "2-277-11923-7" "2-277-11935-0" "2-277-11947-4" "2-277-11956-3" "2-277-11957-1" "2-277-11966-0" "2-277-11975-X" "2-277-11976-8" "2-277-11992-X" "2-277-11996-2" "2-277-11997-0" "2-277-12349-8" "2-277-12355-2" "2-277-12381-1" "2-277-12392-7" "2-277-12397-8" "2-277-12404-4" "2-277-12407-9" "2-277-12410-9" "2-277-12415-X" "2-277-12419-2" "2-277-12459-1" "2-277-12475-3" "2-277-12510-5" "2-277-12547-4" "2-277-12567-9" "2-277-12588-1" "2-277-12594-6" "2-277-12612-8" "2-277-12630-6" "2-277-12659-4" "2-277-13453-8" "2-277-13557-7" "2-277-21000-5" "2-277-21020-X" "2-277-21037-4" "2-277-21038-2" "2-277-21045-5" "2-277-21045-5" "2-277-21047-1" "2-277-21047-1" "2-277-21048-X" "2-277-21057-9" "2-277-21071-4" "2-277-21082-X" "2-277-21083-8" "2-277-21093-5" "2-277-21104-4" "2-277-21105-2" "2-277-21115-X" "2-277-21126-5" "2-277-21127-3" "2-277-21129-X" "2-277-21140-0" "2-277-21159-1" "2-277-21172-9" "2-277-21173-7" "2-277-21194-X" "2-277-21210-5" "2-277-21220-2" "2-277-21221-0" "2-277-21222-9" "2-277-21232-6" "2-277-21233-4" "2-277-21234-2" "2-277-21245-8" "2-277-21268-7" "2-277-21269-5" "2-277-21292-X" "2-277-21328-4" "2-277-21329-2" "2-277-21340-3" "2-277-21341-1" "2-277-21354-3" "2-277-21367-5" "2-277-21368-3" "2-277-21378-0" "2-277-21379-9" "2-277-21380-2" "2-277-21392-6" "2-277-21393-4" "2-277-21396-9" "2-277-21408-6" "2-277-21409-4" "2-277-21419-1" "2-277-21420-5" "2-277-21421-3" "2-277-21434-5" "2-277-21435-3" "2-277-21447-7" "2-277-21448-5" "2-277-21449-3" "2-277-21463-9" "2-277-21474-4" "2-277-21475-2" "2-277-21476-0" "2-277-21491-4" "2-277-21492-2" "2-277-21516-3" "2-277-21517-1" "2-277-21531-7" "2-277-21532-5" "2-277-21535-X" "2-277-21536-8" "2-277-21548-1" "2-277-21549-X" "2-277-21563-5" "2-277-21575-9" "2-277-21576-7" "2-277-21589-9" "2-277-21601-1" "2-277-21603-8" "2-277-21634-8" "2-277-21635-6" "2-277-21648-8" "2-277-21650-X" "2-277-21665-8" "2-277-21666-6" "2-277-21677-1" "2-277-21689-5" "2-277-21690-9" "2-277-21691-7" "2-277-21702-6" "2-277-21708-5" "2-277-21720-4" "2-277-21721-2" "2-277-21722-0" "2-277-21738-7" "2-277-21739-5" "2-277-21741-7" "2-277-21754-9" "2-277-21755-7" "2-277-21756-5" "2-277-21768-9" "2-277-21769-7" "2-277-21781-6" "2-277-21782-4" "2-277-21799-9" "2-277-21800-6" "2-277-21813-8" "2-277-21814-6" "2-277-21825-1" "2-277-21826-X" "2-277-21832-4" "2-277-21849-9" "2-277-21850-2" "2-277-21863-4" "2-277-21864-2" "2-277-21878-2" "2-277-21890-1" "2-277-21891-X" "2-277-21905-3" "2-277-21906-1" "2-277-21921-5" "2-277-21935-5" "2-277-21950-9" "2-277-21962-2" "2-277-21964-9" "2-277-21966-5" "2-277-21968-1" "2-277-21980-0" "2-277-21981-9" "2-277-21996-7" "2-277-21998-3" "2-277-22011-6" "2-277-22012-4" "2-277-22035-3" "2-277-22054-X" "2-277-22055-8" "2-277-22057-4" "2-277-22074-4" "2-277-22075-2" "2-277-22087-6" "2-277-22104-X" "2-277-22105-8" "2-277-22119-8" "2-277-22135-X" "2-277-22135-X" "2-277-22136-8" "2-277-22136-8" "2-277-22150-3" "2-277-22151-1" "2-277-22164-3" "2-277-22165-1" "2-277-22193-7" "2-277-22194-5" "2-277-22223-2" "2-277-22224-0" "2-277-22224-0" "2-277-22232-1" "2-277-22247-X" "2-277-22248-8" "2-277-22261-5" "2-277-22262-3" "2-277-22277-1" "2-277-22278-X" "2-277-22289-5" "2-277-22292-5" "2-277-22294-1" "2-277-22294-1" "2-277-22306-9" "2-277-22307-7" "2-277-22324-7" "2-277-22325-5" "2-277-22340-9" "2-277-22343-3" "2-277-22354-9" "2-277-22355-7" "2-277-22356-5" "2-277-22356-5" "2-277-22371-9" "2-277-22372-7" "2-277-22373-5" "2-277-22389-1" "2-277-22406-5" "2-277-22451-0" "2-277-22552-5" "2-277-22553-3" "2-277-22632-7" "2-277-22670-X" "2-277-22693-9" "2-277-22705-6" "2-277-22780-3" "2-277-23059-6" "2-277-51212-5" "2-501-00072-2" "2-7007-0122-4" "2-7024-0471-5" "2-7024-0695-5" "2-7304-0010-9" "2-7304-0050-8" "2-7304-0074-5" "2-7304-0155-5" "2-7304-0169-5" "2-7304-0181-4" "2-7304-0215-2" "2-7316-0182-5" "2-7340-0110-1" "2-7340-0111-X" "2-7340-0113-6" "2-7340-0115-2" "2-7340-0122-5" "2-7340-0179-9" "2-8011-0155-9" "2-8011-0156-7" "2-8011-0174-5" "2-8011-0181-8" "2-8011-0213-X" "2-8011-0238-5" "2-8011-0239-3" "2-8011-0258-X" "2-8011-0260-1" "2-8011-0290-3" "2-8011-0291-1" "2-80400-230-6" "2-86215-107-6" "2-86215-128-9" "2-86215-139-4" "2-906843-26-1")) (defvar failing-isbns '("0-259-00650-7" "2+277-21920-7" "2-01-038171-4" "2-206-00608-8" "2-207-300071-4" "2-207-30022-5" "2-207-30355-7" "2-207-31003-1" "2-207-31010-4" "2-207-31371-3" "2-208-070383-8" "2-227-21707-7" "2-227-22248-8" "2-244-21564-3" "2-253-02300-X" "2-253-031496" "2-253-03170-0" "2-258-01715-1" "2-259-00696-7" "2-259-02169-3" "2-266-00942-8" "2-266-009885-0" "2-266-01426-1" "2-266-0245-5" "2-266-0365-8" "2-27304-0145-8" "2-27340-0113-6" "2-27340-0115-2" "2-277-01179-X" "2-277-11323-0" "2-277-11373-0" "2-277-1140-5" "2-277-11418-4" "2-277-11468-0" "2-277-13362-X" "2-277-21602-8" "2-277-21963" "2-277-2306-9" "2-277-37010-4" "2-59-00766-X" "2-7304-01881-" "2-7304-0248-1" "2-7304-0257-2" "2-7304-0360-2" "2-7304-0381-5" "2-7340-0135-Z" "2-86-676-278-9" "20-277-01917-1")) ;; check-isbns.el ends here edb-1.31/tests/ebatch.in0000444000175000017500000000031011016014113013260 0ustar ttnttn#!/bin/sh emacs=${EMACS-emacs} loadfrom=`cd @abs_top_srcdir@/lisp ; pwd` if [ x"$DEBUG" = x ] ; then exec 1>/dev/null 2>&1 ; fi exec $emacs -batch --eval "(add-to-list 'load-path \"$loadfrom\")" "$@" edb-1.31/tests/friendly.test0000555000175000017500000000005510745370012014243 0ustar ttnttn":"; exec ./ebatch -l $0 (require 'database) edb-1.31/tests/isbn.test0000555000175000017500000000014510745370012013362 0ustar ttnttn":"; exec ./ebatch --no-site-file -l $0 -l $srcdir/check-isbns.el -f check-isbns (require 'database) edb-1.31/tests/null.test0000555000175000017500000000077010745370012013405 0ustar ttnttn":"; exec ./ebatch --no-site-file -l $0 (require 'database) (let ((ex (expand-file-name "../examples" (getenv "srcdir")))) (edb-interact (expand-file-name "null.edb" ex) (expand-file-name "null" ex))) (message "%s" (progn (list-buffers) (with-current-buffer "*Buffer List*" (buffer-string)))) (add-to-list 'load-path (expand-file-name "lisp" (car load-path))) (require 'edb-meta) (edb-meta) (message "%s" (buffer-string)) (kill-buffer nil) edb-1.31/tests/skram.test0000555000175000017500000000045310745370012013546 0ustar ttnttn":"; exec ./ebatch --no-site-file -l $0 (require 'database) (cd (format "%s/skram" (or (getenv "topsrcdir") ".."))) (shell-command (format "%s sk3" (or (getenv "MAKE") "make"))) (setq res (shell-command-to-string "diff -Bbw skram.data sk3")) (unless (string= "" res) (error "diff showed:\n%S" res))