BibTool/README.md0000644000175100017510000000716112646463060012323 0ustar genegene---------------------------------------------------------------------- ###### ############ ####### ############ ## ## ## ## ## ## ##### ## #### #### ## ####### ## ###### ## ###### ###### ## ####### ## ## ## ## ## ## ## ## ## ## ## ## ###### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ####### ## ###### ## ###### ###### ####### ###### ## ##### ## #### #### ####### ---------------------------------------------------------------------- BibTool: A Tool for Manipulating BibTeX Data Bases BibTeX provides an easy to use means to integrate citations and bibliographies into LaTeX documents. But the user is left alone with the management of the BibTeX files. The program BibTool is intended to fill this gap. BibTool allows the manipulation of BibTeX files which goes beyond the possibilities --- and intentions --- of BibTeX. The possibilities of BibTool include * Pretty-printing BibTeX data bases adjustable by lots of parameters. * Syntactic checks with error recovery superior to BibTeX and helpful error messages. * Semantic checks can be specified by the user. * Sorting and merging of BibTeX data bases according to a free definable sort key. * Generation of uniform reference keys according to predefined rules or according to an own specification. * Selecting references used in one publication which are found by analyzing an .aux file. * Selecting references by a set of criteria (regular expressions). * Controlled rewriting of fields utilizing regular expressions to specify the rewriting rules. * Macro (String) expansion to eliminate the need of extra string definitions. * Collecting statistics about one or more BibTeX data bases. BibTool contains a documentation written in LaTeX of more than 75 pages (and still growing). BibTool is written in C and has been compiled on various operating systems like flavors of UN*X and MSDOG machines. It is distributed in source code. No compiled versions are available from the author (Useless to ask!). # CTAN Download BibTool can be obtained from the CTAN archives: * http://mirrors.ctan.org/biblio/bibtex/utils/bibtool Get the file BibTool-x.xx.tar.gz where x.xx is the version number. Unpack it with the command (on UN*X) gunzip < BibTool-x.xx.tar.gz | tar -xvf - It will create a directory named BibTool which contains the installation instructions in the file install.tex. A signature for the source bundle is provided as well. My public key can be found on http://pgp.mit.edu/. You should search for my email address. # Licenses The sources of BibTool are distributed under the GNU General Public License version 2 or later. The documentation is distributed under the Creative Commons Attributation-Share Alike 3.0 License. The distribution of BibTool contains the following third-party software which is released under their own licenses: * GNU regex library 0.12 is located in the directory regex-0.12. It is distributed under the GNU General Public License version 2 or later. * mkdirchain consists of the file mkdirchain. It is in the public domain. * install-sh consists of the file install-sh. It is distributed under the MIT license contained in this file. ---------------------------------------------------------------------- Enjoy it! Gerd Neugebauer mailto:gene@gerd-neugebauer.de BibTool/install.tex0000644000175100017510000004540212646426064013237 0ustar genegene%%*** install.tex ************************************************************** %% %% This file is part of BibTool. %% It is distributed under the Creative Commons Attribution-Share %% Alike 3.0 License. %% %% (c) 2010-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %%***************************************************************************** \documentclass[11pt,a4paper]{scrartcl} \usepackage[latin1]{inputenc} \usepackage{hyperref} \newcommand\code[1]{\texttt{#1}} \newcommand\file[1]{\textsf{#1}} \newcommand\BS{\(\backslash\)} \newcommand\BibTool{{\sc Bib\hskip-.1em\-% \mbox{T\hskip-.15emo\hskip-.05emo\hskip-.05eml}}} \newcommand\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} \date{} \begin{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \title{\BibTool{} Installation} \author{Gerd Neugebauer} \maketitle \BibTeX{} provides an easy to use means to integrate citations and bibliographies into \LaTeX{} documents. But the user is left alone with the management of the \BibTeX{} files. The program BibTool is intended to fill this gap. \BibTool{} allows the manipulation of \BibTeX{} files which goes beyond the possibilities --- and intentions --- of \BibTeX{}. The possibilities of \BibTool{} include \begin{itemize} \item Pretty-printing \BibTeX{} data bases adjustable by lots of parameters. \item Syntactic checks with error recovery superior to \BibTeX{} and helpful error messages. \item Semantic checks can be specified by the user. \item Sorting and merging of \BibTeX{} data bases according to a free definable sort key. \item Generation of uniform reference keys according to predefined rules or according to an own specification. \item Selecting references used in one publication which are found by analyzing an .aux file. \item Selecting references by a set of criteria (regular expressions). \item Controlled rewriting of fields utilizing regular expressions to specify the rewriting rules. \item Macro (String) expansion to eliminate the need of extra string definitions. \item Collecting statistics about one or more \BibTeX{} data bases. \end{itemize} \BibTool{} contains a documentation written in \LaTeX{} of more than 75 pages (and still growing). \BibTool{} is written in C and has been compiled on various operating systems like flavors of UN*X and MSDOG machines. It is distributed in source code. No compiled versions are available from the author (Useless to ask!). \BibTool{} can be obtained from the CTAN archives: \begin{itemize} \item \url{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibtool} \end{itemize} Get the file BibTool-x.xx.tar.gz where x.xx is the version number. Unpack it with the command (on UN*X) \begin{verbatim} gunzip < BibTool-x.xx.tar.gz | tar -xvf - \end{verbatim} It will create a directory named BibTool which contains this installation instructions in the file \file{install.tex}. So just read on. %This file contains instructions and hints for the compilation of \BibTool{}. \newpage \tableofcontents \newpage \section{Introduction} \BibTool{} is known to work on the following operating systems/C compilers: (At least an earlier version has been compiled successfully on them.) \begin{description} \item[Debian] gcc \item[CentOS] gcc \item[Ubuntu] gcc \item[SuSE] gcc \item[Windows XP/Cygwin] gcc \item[Windows 7/Cygwin 1.7] gcc \item[SparcStation/Solaris2.4] gcc \item[Sun4/SunOS4.1.*] cc, gcc \item[Sun3/SunOS4.1.1] cc \item[HP 9000/4??/HP UX ??] cc \item[Atari ST/TOS 1.2] Laser C, Pure C \end{description} I have been informed that \BibTool{} has been compiled on the following machines/operating systems (and maybe some more that I have forgotten to add to this list;-): \begin{description} \item[gentoo] gcc \item[OS X Mavericks] \item[AIX 3.2.5] gcc \item[AIX 4.1.4] \item[Amiga] SAS/C \item[DEC Alpha/OSF/1] \item[HP 9000/778/HP-UX 10.20] gcc 2.7.2.3 \item[MIPS/Ultrix4.4] gcc 2.4.5 \item[MIPS/RISCos 4.52] gcc \item[MSDOS,OS/2,Win32,WinNT] emx, dj, Watcom C, MSC \item[MS-Windows 4.0, Sp 6] Cygwin \item[IBM PC] 486DX2-66, OS/2 Merlin 4.0 FixPack \#5. EMX v.0.9c+GCC+dmake 4.0 \item[NeXT] \item[SGI Indigo2/IRIX 6.2] cc \item[Windows XP 32 bits] MinGW with GCC 4.6.1 \item[Windows 7] Cygwin 1.7 with gcc \item[Windows 7] MinGW with gcc 4.8.1 \end{description} If you compile \BibTool{} on other systems drop me a mail. I'm interested to support a broad variety of systems/compilers. \begin{quote} Gerd Neugebauer\\ Im Lerchelsböhl 5\\ 64521 Groß-Gerau (Germany) Net: \url{gene@gerd-neugebauer.de} \end{quote} You can also send me a mail if you encounter problems in compiling \BibTool{}, or crashes, or shows unexpected (contradicting the documentation) behavior of the final program. Please enclose a precise description what went wrong. Include the version numbers of \BibTool{}, your computer, your operating system, and your C compiler. If you encounter unexpected behavior of \BibTool{} enclose your resource file(s) and a \emph{small} \BibTeX{} file demonstrating the problem. Describe how you have invoked \BibTool{} (arguments) and justify why you think that there is a problem. I know that this sounds like work. But otherwise I will not be able to give you proper advice or find a bug in the sources. \section{Prerequisites} To install \BibTool{} you need: \begin{itemize} \item A C compiler. ANSI-C is not required but highly recommended. Several library functions are expected. You will see if your linker complains. \item A running version of make is recommended. \end{itemize} \section{Generic Installation Procedure}\label{generic} See if there is a special section for your computer/C compiler and follow the instructions given there. Most probably you will be directed back into this section after some initial actions. See section~\ref{kpathsea} and see if it applies to your setting. To install \BibTool{} you can try to apply the following instructions: \begin{enumerate} \item Copy one of the prepared makefiles to \file{makefile} and adjust it according to your C compiler. The following makefiles should be present in the distribution: \begin{description} \item[makefile.unx] This is the generic makefile. Especially it is for all UN*X systems and may provide a basis for compilation on systems not explicitly mentioned here. \item[makefile.dos] This is the makefile for MSDOS based machines. \item[makefile.ata] This is the makefile for Atari ST/TT computers. \item[makefile.ami] This is the makefile for Amiga computers (with SAS/C). \end{description} Edit the \file{makefile} and adjust the settings in the configuration section according to your needs. Maybe you have to adapt the name and options for your C compiler. (Most of the time I prefer the GNU C compiler) Maybe you want to change the location for the installation target, even though reasonable defaults are provided. \item Look into the file \file{include/bibtool/config.h} to see if it fits your operating system and C compiler. Adjust things as required. Most probably you do not have to change anything in this file. This file is mainly for those with an old C compiler (non-ANSI). \item If you want to configure some of the internals of \BibTool{} you can have a look into \file{include/bibtool/bibtool.h.} It contains the internal configuration options which used to be in \file{config.h } prior to release 2.39. Most probably there is no need to change the defaults given there. One exception is the support for another language by specifying additional words to be ignored. (Maybe I could include them into the distribution; thus drop me a mail if you do so) \item If you have a working makedepend command run \begin{verbatim} make depend \end{verbatim} Otherwise just skip this step. It is only helpful if you compile \BibTool{} more than once. This might cause problems if the makedepend command does not fit the C compiler used (e.g. proprietary makedpend together with gcc). This results in unknown files to show up. In this case also skip this step and revert to the original makefile. \item Afterwards run \begin{verbatim} make \end{verbatim} Most probably this should produce the executable \file{bibtool} (or \file{bibtool.exe}, or \file{bibtool.ttp}, or \ldots) in the current directory. \item If you have tried the command bibtool in the current directory you can install it with \begin{verbatim} make install \end{verbatim} to install the executable and the libraries and \begin{verbatim} make install.man \end{verbatim} to install the UN*X man pages. This is only useful if you can make use of them, i.e. on a UN*X-like system. \item To get rid of all intermediate files run \begin{verbatim} make clean \end{verbatim} \item To prepare the documentation contained in the sub-directory \file{doc} go into the \file{doc} subdirectory and run \begin{verbatim} latex bibtool latex bibtool bibtex bibtool makeidx bibtool latex bibtool latex bibtool \end{verbatim} \begin{verbatim} latex ref_card latex ref_card bibtex ref_card makeidx ref_card latex ref_card latex ref_card \end{verbatim} The makeidx program may be named differently on your system or missing at all. In this case you can omit this step and do without the index. On UN*X you can try \begin{verbatim} make doc \end{verbatim} in the main directory or \begin{verbatim} make \end{verbatim} in the \file{doc} directory which tries to perform the steps given above. The documentation is written in a way that either \LaTeX{} or \LaTeX2.09 can be used to compile it. I had a bug report about a real ancient \LaTeX2.09 and I am not sure I have completely fixed it. Thus the best is to use an up-to-date \LaTeX. There might be problems when files produced by \LaTeX2.09 should be read by \LaTeXe{} and vice versa. In this case you can try to remove the intermediate files \begin{verbatim} bibtool.toc bibtool.ind \end{verbatim} and follow the instruction for making the documentation from the beginning. \end{enumerate} \section{Installation on UNIX} Some special preparations have been made for UNIX systems. autoconf scripts are provided which try to find out the characteristics of the system automatically. General instructions: \begin{enumerate} \item Run the configure script with the command: \begin{verbatim} ./configure \end{verbatim} The following options are useful for configure: \begin{description} \item [--with-kpathsea] try to find the kpathsea library either in the current directory or in the previous directory. Thus you can place the \BibTool{} directory in the same directory where the directory kpathsea resides or you can put the kpathsea directory in in the \BibTool{} directory. (default) (See also section~\ref{kpathsea}) \item [--without-kpathsea] disable the search for the kpathsea library. \item [--prefix=PREFIX] install architecture-independent files in PREFIX [/usr/local] \item [--exec-prefix=EPREFIX] install architecture-dependent files in EPREFIX [same as prefix] \item [--bindir=DIR] the bibtool executable is stored in DIR [EPREFIX/bin] \item [--libdir=DIR] the \BibTool{} directory containing certain resource files are stored in DIR [EPREFIX/lib] \item [--mandir=DIR] the manual pages bibtool.1 is stored in DIR [PREFIX/man] \end{description} \item Continue with the item C in section \ref{generic}. \end{enumerate} \section{Installation on MSDOS-like Computers} This section some hints on the compilation of \BibTool{} on MSDOS computers. These adaptions are mainly due to the efforts of Josef Spangler (JS@rphnw3.ngate.uni-regensburg.de). All credits go to him. Any remaining problems should be blamed on my ignorance. General instructions: \begin{enumerate} \item Copy \file{makefile.dos} to \file{makefile} and adjust it according to your C compiler. \item Edit \file{include/bibtool/config.h} and \file{include/bibtool/bibtool.h} to adjust it to your needs. Normally you should be interested only in the support of em\TeX{} at the end of \file{include/bibtool/bibtool.h}. \item Copy MSDOS\BS link.* to the source directory. \item Depending on the C compiler do the following: \begin{itemize} \item dj (GNU C port) \begin{verbatim} make dj \end{verbatim} \item emx (GNU C port) \begin{verbatim} make emx \end{verbatim} Maybe you have to set the environment variable EMX to point to the installed EMX directory. \item Watcom C 386 (32 Bit Compiler for Dos, OS/2 2.x, Win32 and WinNT) \begin{verbatim} make wat \end{verbatim} \item Microsoft C 6.00A (16 Bit Dos and OS/2 1.x) \begin{verbatim} make msc \end{verbatim} \item Borland C++ 3.1 (16 Bit Dos) Go and get another compiler. Or, even better do the port and send me the diffs :-) \end{itemize} \item If you have tried the command bibtool in the current directory you can install it with \begin{verbatim} make install \end{verbatim} \item Make the documentation according to step H in section \ref{generic}. \end{enumerate} \section{Installation on Amiga} This section contains some hints on the compilation of \BibTool{} on Amiga computers. These adaptions are mainly due to the efforts of Andreas Scherer (SCHERER@genesis.informatik.rwth-aachen.de). All credits go to him. Any remaining problems should be blamed on my ignorance. This section describes the installation procedure if you are using the SAS/C compiler on Amiga. General instructions: \begin{enumerate} \item Copy \file{makefile.ami} to \file{SMakefile} and adjust it accordingly. \item Edit the file \file{include/bibtool/config.h} and \file{include/bibtool/bibtool.h} and adjust it to your needs. There should not be much for you to change. \item \begin{verbatim} make \end{verbatim} \item If you have tried the command bibtool in the current directory you can install it with \begin{verbatim} make install \end{verbatim} \item Make the documentation according to step H in section \ref{generic}. \end{enumerate} \section{Installation without make} \begin{enumerate} \item Adjust the settings in the files \file{include/bibtool/config.h} and \file{include/bibtool/bibtool.h} to fit your C compiler and operating system. \item Compile all .c files in the base directory. The macros REGEX and maybe MSDOS should be defined. The subdirectory \file{regex-0.12} should be included in the include search path. A typical compile command looks like \begin{verbatim} cc main.c -c -o main.o -DREGEX -DMSDOS -Iregex-0.12 -I. \end{verbatim} \item Compile \file{regex.c} in the regex-0.12 subdirectory and move the object file into the base directory (The one containing this file). \item Link together all object files to get the executable bibtool. (maybe include the kpathsea library; see section \ref{kpathsea}) \item Run \LaTeX{} on \file{bibtool.tex} in the \file{doc} sub-directory to produce the documentation. (see step H in section \ref{generic} for details) \end{enumerate} \section{Using the kpathsea library}\label{kpathsea} The kpathsea library provides a very flexible way to specify the search path for files. This library is already used by the web2c distribution of Karl Berry and the te\TeX{} distribution. To achieve compatibility with those \TeX{} systems you can try to make \BibTool{} use the same library. The kpathsea library is currently NOT CONTAINED in the distribution of \BibTool{} since this is an experimental feature. You can get kpathsea from the same location where you got \BibTool{}. Fetch the file \file{kpse2-6.tar.gz} or \file{kpse2-6.zip}. Unpack this file. Enter the directory kpse2-6 and use the commands `./configure' and `make' to create the library. This works at least on Unix platforms. For porting to other platforms I would like to get some feedback. ATTENTION: The kpathsea library has to exists before \BibTool{} is made! If you are using configure then the option \texttt{--with-kpathsea} enables the inclusion of the kpathsea routines if the library is found. To use the library you can just provide three definitions in the makefile. See the section about kpathsea in \file{makefile} for explanations. Alternatively you have to provide the appropriate options to the C compiler yourself. Note: the searching for \BibTeX{} files with the kpathsea library is different from the \BibTool{} built-in searching. Some resources are no longer taken into account when this library is used. Note: kpathsea is only used to search for \BibTeX{} files. All other files are still searched with the traditional \BibTool{} searching mechanism. This might change soon. \section{Problems and Porting} Well, if the procedures described above don't work I have some hints. These hints may also be useful if you plan to port \BibTool{} to other operating systems or C compilers. First of all a small list of assumptions that I use. \begin{itemize} \item On ANSI systems there should be no problem at all. There is some support for non-ANSI systems. This support can be improved. (I don't know if it's worthwhile to do so). \item \BibTool{} has been developed on UN*X (SunOS) and UN*X-like systems (Atari). Such file/directory naming conventions found their way into the code. Single character delimiters between directories and files can be modified in a resource file. \item ASCII encoding is assumed. I role my own \file{type.h} instead of using \file{ctypes.h}. This has mainly historical reasons. Maybe this code should be rewritten to be adapted at make time. If you port \BibTool{} to a non-ASCII machine the table of characters (allowed[]) in \file{type.h} has to be adapted -- at least (please send me the diffs). \item Maybe some BSD-isms found their way into the code even if I am not aware of it. \end{itemize} \section{The C Interface} The C interface to \BibTool{} is described in the document \file{doc/c\_lib.dvi}. To create this document run \LaTeX{} and makeindex on the file \file{c\_lib.tex} in the \file{doca} sub-directory: \begin{verbatim} latex c_lib makeindex c_lib latex c_lib latex c_lib \end{verbatim} Read this document. I would like some kind of feedback for this attempt. Attention: This documentation is experimental. Some things are likely to be changed soon. \section{ The Tcl/Tk Interface} The Tcl/Tk interface is called BibTcl. It is contained in the BibTcl subdirectory. See the file \file{README} in this directory for details. \end{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Local Variables: % mode: latex % TeX-master: nil % End: BibTool/COPYING0000644000175100017510000004307612554153057012104 0ustar genegene GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. BibTool/Changes.tex0000644000175100017510000013452612646465421013147 0ustar genegene%%*** Changes.tex ************************************************************* %% %% This file is part of BibTool. %% It is distributed under the Creative Commons Attribution-Share %% Alike 3.0 License. %% %% (c) 2010-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %%----------------------------------------------------------------------------- %% Usage: latex Changes %% latex Changes %%***************************************************************************** \documentclass[11pt,a4paper]{scrartcl} \usepackage{multicol} \newenvironment{Developers}{}{} \newcommand\Developer[3]{} \newcommand\Arg[1]{\texttt{#1}} \newcommand\rsc[1]{\texttt{#1}} \newcommand\File[1]{\textsf{#1}} \newcommand\BibTool{\textsc{BibTool}} \newcommand\BibTcl{\textsc{BibTcl}} \newcommand\BibTeX{\textsc{Bib}\TeX} \newenvironment{Release}[2]{% \section*{Release #1 {\normalsize[#2]}} \begin{itemize} }{\end{itemize}} \newenvironment{Fix}[1]{\item }{} \newenvironment{New}[1]{\item }{} \newenvironment{Doc}[1]{\item }{} \newenvironment{Update}[1]{\item }{} \newcommand\BS{\char`\\} \begin{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \title{\BibTool{} Change Log} \author{Gerd Neugebauer} \date{} \maketitle \begin{Developers} \Developer{gene}{Gerd Neugebauer}{gene@gerd-neugebauer.de} \end{Developers} \begin{multicols}2 % ===================================================================== \begin{Release}{2.63}{January 16, 2016} \begin{Fix}{gene} Omission of the previous release fixed. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.62}{January 16, 2016} \begin{Fix}{gene} Combined rewrite and delete bug fixed. \end{Fix} \begin{Update}{gene} Minor improvements for the distribution. \end{Fix} \begin{Update}{gene} \File{README} renamed to \File{README.md} to comply with the conventions of the GitHub repository. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.61}{July 12, 2015} \begin{New}{gene} New resource \rsc{rename.field} introduced to conditionally rename a field. \end{New} \begin{Update}{gene} Typedef \verb|String| for \verb|Uchar*| and used across. \end{Update} \begin{Fix}{gene} Duplicate file \File{doc/bibtool.tex} in the distribution tar ball eliminated. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.60}{June 9, 2015} \begin{Fix}{gene} The field name and other symbols may start with any allowed character. Non-alpha characters at the beginning are treated as warning only. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.59}{March 14, 2015} \begin{Fix}{gene} Fix in \File{print.c} to omit an empty line after overflowing lines. \end{Fix} \begin{Fix}{gene} Fix in \File{print.c} to avoid an overflow situation. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.58}{February 9, 2015} \begin{Update}{gene} Library \File{tex\_def.rsc} extended with the primitives \verb|\i| and \verb|\j|. \end{Update} \begin{Update}{gene} The source tar is signed. The key of the author can be obtained from \texttt{pgp.mit.edu}. \end{Update} \begin{Update}{gene} \texttt{Test} renamed to \texttt{test}. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.57}{April 18, 2014} \begin{Fix}{gene} Segfault in deTeX fixed. \end{Fix} \begin{Fix}{gene} Compiler warnings silenced. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.56}{April 14, 2014} \begin{Fix}{gene} Disambiguating numbers adapted to fit to documentation. \end{Fix} \begin{Fix}{gene} Configuration of regex fixed to work on Linux. \end{Fix} \begin{Fix}{gene} Documentation typos fixed. \end{Fix} \begin{Fix}{gene} Signed characters fro translation tables changed to unsigned. \end{Fix} \begin{Fix}{gene} Autoconf configuration improved. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.55}{April 15, 2012} \begin{New}{gene} Library \File{biblatex.rsc} added. It contains capitalizations of fields used in bib\LaTeX. \end{New} \begin{Fix}{gene} Fix for a misbehaviour when selecting entries according to an aux file with deeply nested @strings. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.54}{February 21, 2012} \begin{New}{gene} Command line parameter \Arg{-V} documented. \end{New} \begin{New}{gene} Resource \rsc{key.make.alias} added to create new \texttt{@ALIAS} records for any newly generated key. \end{New} \begin{New}{gene} Resource \rsc{apply.alias} added to expand the \texttt{@ALIAS} records. \end{New} \begin{New}{gene} Resource \rsc{apply.include} added to expand the \texttt{@INCLUDE} records. \end{New} \begin{New}{gene} Resource \rsc{apply.modify} added to expand the \texttt{@MODIFY} records. \end{New} \begin{Update}{gene} Error message for \Arg{-o} without parameter added. \end{Update} \begin{Fix}{gene} \texttt{@ALIAS} and \texttt{@INCLUDE} records where not printed. This has been fixed. \end{Fix} \begin{New}{gene} A test suite for \BibTool{} has been integrated. It requires Perl to be present on the system on which the tests should be run. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.53}{September 25, 2011} \begin{Update}{gene} In \texttt{tex.define} spaces before the = are ignored instead of leading to unwanted definitions. \end{Update} \begin{Fix}{gene} An intialization error showed up on MacOS. This has been fixed. \end{Fix} \begin{Fix}{gene} The prepared makefiles for various operating systems missed an entry for \texttt{crossref.[cho]}. \end{Fix} \begin{Fix}{gene} Typo in help text and copyright year fixed. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.52}{June 6, 2011} \begin{Fix}{gene} A few incompatibilities with signed and unsigned characters which showed up on MacOS only have been fixed. \end{Fix} % \end{Release} % ===================================================================== % \begin{Release}{2.52}{April 26, 2011} \begin{Fix}{gene} A few compiler warnings have been fixed. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.51}{May 12, 2010} \begin{Fix}{gene} Bugfix in \File{names.c}: The classification of name parts erroneously has used a wrong translation under certain circumstances. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.50}{May 12, 2010} \begin{Fix}{gene} Bugfix in \File{names.c}: The classification of name parts erroneously has used a wrong translation under certain circumstances. \end{Fix} %\end{Release} % ===================================================================== %\begin{Release}{2.50}{February 6, 2010} \begin{Fix}{gene} Bugfix in \File{key.c}: The classification of name parts erroneously has considered, to be a first name under certain circumstances. This has been improved. \end{Fix} \begin{Fix}{gene} Improvement in \File{names.c} and \File{key.c} concerning printing in debug mode. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.49}{February 8, 2007} \begin{New}{gene} New resource \rsc{expand.crossref} introduced. This resource enables the expansion of fields inherited via the crossref mechanism. \end{New} \begin{Fix}{gene} Bugfix in \File{names.c}: The classification of name parts erroneously has considered the initials V., I., and X. to be Roman numerals belonging to the jr part under special circumstances. This has been improved. \end{Fix} % ===================================================================== %\begin{Release}{2.49}{January 5, 2010} \begin{New}{gene} Name formatting now uses a fractional part to restrict the number of name parts considered. \end{New} % ===================================================================== %\begin{Release}{2.49}{February 8, 2007} \begin{New}{gene} New resource \rsc{expand.crossref} introduced. This resource enables the expansion of fields inherited via the crossref mechanism. \end{New} \begin{Fix}{gene} Bugfix in \File{print.c}: Some national characters have been lost. It was necessary to use an unsigned character as elsewhere. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.48}{August 6, 2004} \begin{New}{gene} Resource \rsc{print.terminal.comma} introduced. This resource can be used to request commas after the last record even if it contradicts the rules of \BibTeX. \end{New} \begin{New}{gene} \File{makefile.in} for configure extended to support the variable \texttt{INSTALLPREFIX} to be prepended to installation directories. \end{New} \begin{Fix}{gene} Bugfix in \File{main.c}: Some compilers didn't like the method true(). \end{Fix} \begin{Fix}{gene} Bugfix for kpathsea under Suse 9.1. \end{Fix} \begin{Fix}{gene} Bugfixes in expansion. \end{Fix} %\end{Release} % ===================================================================== %\begin{Release}{2.48}{February 8, 2004} \begin{Update}{gene} \BibTcl{} has been taken out of the default making since it has caused troubles on several machines. \end{Update} \begin{Update}{gene} The printing of Strings honors now the dependencies that \BibTeX{} relies on. This has been accomplished by a change in the printing routine for databases. No new resource is involved. \end{Update} \begin{Update}{gene} Minor modification to the C API. \end{Update} \begin{New}{gene} Feature: When searching for an aux file and none is found then \texttt{.aux} is appended and a reopen is tried with the new name. \end{New} \begin{Update}{gene} Feature: When \rsc{expand.macros} is set the macros will be suppressed automatically. No need to set \rsc{print.entry.types} any more. \end{Update} \begin{New}{gene} The boolean resource \rsc{select.crossrefs} has been introduced. This resource can be used to force cross-referenced entries for selected entries to be included in the output. \end{New} \begin{Update}{gene} Feature: deleted entries are not reported as "`written"' by the statistics any more. \end{Update} \begin{Fix}{gene} Bugfix: Bug in extracting by aux file. Crossrefed entries where sometimes ignored. \end{Fix} \begin{Fix}{gene} Bugfix: Bug in parsing of backslashes in resources has been fixed. Unfortunately this bug appeared in one of the examples in the manual. \end{Fix} \begin{Fix}{gene} Bugfix: Bug in expansion introduced in 2.47 has been fixed. An error occurred when expanding macros. \end{Fix} \begin{New}{gene} The resource loading with \rsc{resource} now issues a warning when the file could not be found. \end{New} \begin{Doc}{gene} The meaning of post for the format specifiers \%d and \%D has been documented. \end{Doc} \begin{Fix}{gene} Bugfix: \BibTool{} has misinterpreted pre for the format specifier \%t and \%T due to an over-optimization. This has been fixed. \end{Fix} \begin{Fix}{gene} Bugfix: \BibTool{} has ignored \rsc{preserve.key.case} for cross-referenced keys. This has been fixed. \end{Fix} \begin{Fix}{gene} Bugfix: Some compilers don't like it if static strings are modified. Thus I have made them dynamic. \end{Fix} \begin{New}{gene} Experimental feature \rsc{regexp.syntax} added. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.47}{January 16, 2003} \begin{Fix}{gene} Bugfix: \BibTool{} looped when parsing unbalanced blocks due to a too short type in \File{parse.c}. This has been fixed and some error messages have been improved. \end{Fix} \begin{Doc}{gene} Some additions to the documentation due to Patrice Dumas. \end{Doc} \begin{New}{gene} Resource \rsc{fmt.word.separator} introduced. This resource can be used to mark additional characters to be considered as word separators. \end{New} \begin{Fix}{gene} Bugfix: \BibTool{} looped when a malformed string of some kind was given to expansion. This has been fixed in \verb|expand()|. \end{Fix} \begin{Fix}{gene} Bugfix: \BibTool{} crashed when called with empty format string due to an uninitialized variable. This has been fixed in \verb|parse_fmt()|. \end{Fix} \begin{Doc}{gene} Bugfix: Documentation bug fixed. The default for \rsc{sort.key} should be \verb|%s($key)|. This has been fixed in \File{Lib/default.rsc} and the manual. \end{Doc} \end{Release} % ===================================================================== \begin{Release}{2.46}{February 12 2002} \begin{New}{gene} Resource \rsc{sort.cased} introduced to allow the sorting order to take advantage of upper and lower case characters. The default is false which is the previous behavior. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.45}{October 22 2001} \begin{New}{gene} Resource \rsc{suppress.initial.newline} introduced to suppress the empty line at the beginning of the output file. \end{New} \begin{Fix}{gene} Bugfix: Some C compilers don't like the initialization of static variables with \texttt{stderr}. The code has been moved to a initialization routine. \end{Fix} \begin{Fix}{gene} Bugfix: \texttt{-R} disables the reading of the resource at the end of processing of command line arguments. \end{Fix} \begin{Fix}{gene} Bugfix: Parsing of select arguments with backslashes were not treated correctly. \end{Fix} \begin{Doc}{gene} Minor documentation bugs fixed. \end{Doc} \end{Release} % ===================================================================== \begin{Release}{2.44}{April 7 1999} \begin{Fix}{gene} Key generation fixed to expand \BibTeX{} strings. The current behavior is likely to change again in a future release. \end{Fix} \begin{Update}{gene} Updated to work with kpathsea 3.1 (partially). \end{Update} \begin{New}{gene} Searching for the kpathsea library is now the default in the configure script. Thus it is possible to simply place \BibTool{} in a web2c tree. This only requires that the directory is named bibtool and bibtool is added to the filelists in Makefile, configure, and configure.in of the web2c main directory. \end{New} \begin{Fix}{gene} \rsc{check.double} message improved. \end{Fix} \begin{Fix}{gene} Initialization bug for kpathsea fixed. \end{Fix} \begin{Fix}{gene} Bugfix for cross referencing: normalization to lowercase was missing twice. \end{Fix} \begin{Fix}{gene} Bugfix in the \TeX{} reading routines: spaces after active characters are not ignored. All characters are treated as unsigned. This seems to be preferrable for extended ASCII characters. \end{Fix} \begin{Update}{gene} Key generation routines adapted to work with multiple databases. The symbol table is no longer abused to store information for the key generation. This may slow down the key generation a little bit. If it turns out to be a problem I will use a better algorithm. \end{Update} \begin{Update}{gene} Minor modifications in makefiles. \end{Update} \begin{New}{gene} The configuration of \BibTcl{} is now done automatically. \end{New} \begin{New}{gene} New datatype introduced: \verb|Uchar| will hold UniCode characters in a future release. I just have to find regexp routines to work with UTF-8. \end{New} \begin{Update}{gene} Extraction extended to allow negation of the regular expression/string matching result. New resources \rsc{select.non} and \rsc{select.by.non.string} to specify such a request. C function \verb|add_extract()| extended to cover negated values and the former function \verb|add_s_extract()|. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.43}{} \begin{New}{gene} Additional library \rsc{braces.rsc} to translate quotes as field delimiters into braces. \end{New} \begin{Update}{gene} \verb|bibtool -h| reports now also the library path. This can be used by external scripts to find the installation directory of \BibTool. \end{Update} \begin{Fix}{gene} Bugfix: comments are no longer crippled. \end{Fix} \begin{Fix}{gene} Minor bugfix in rewriting code: empty pattern works again. \end{Fix} \begin{Fix}{gene} The regression tests have revealed a bugfix in the key generation code. I am not aware of the change that has let to this effect but the new behaviour is correct. Before, the macro expansion was suppressed under certain circumstances. \end{Fix} \begin{New}{gene} \BibTcl: \verb|bibtool count db| added. \end{New} \begin{Fix}{gene} \BibTcl: \verb|bibtool missing| ignores the case of the field name. \end{Fix} \begin{Update}{gene} \BibTcl: consistently renaming \verb|record| to \verb|entry|. \end{Update} \begin{Fix}{gene} Minor modifications of makefile to correctly generate \File{libbib.a} and install the header files. \end{Fix} \begin{Update}{gene} Reorganization of the code; header files are now in their own directory. I don't have the appropriate information for some DOS compilers yet. Thus minor modifications in the makefile might be required. \end{Update} \begin{New}{gene} C function \verb|entry_statistics()| removed. The functionality can be modeled with the new C function \verb|db_count()|. This takes into account that several databases can be managed internally. \end{New} \begin{Update}{gene} C function \verb|save_word()| renamed to \verb|add_word()|. \verb|list_words()| removed since it has been used for debugging only. \end{Update} \begin{Update}{gene} EntryTypes implementation changed. The API doesn't change. Data type \verb|StringTab| is now local to \File{symbols.c}. Data type \verb|Rule| is now local to \File{rewrite.c}. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.42}{} \begin{New}{gene} New selection operation introduced. The selection with regular expressions is complemented by a selection according to simple substrings. This selection is initiated with the new resource \rsc{select.string} which takes the same arguments as the resource \rsc{select} but does comparison for a substring instead of regular expression matching. The value of \rsc{select.case.sensitive} is taken into account but at runtime and not at specification time. Certain characters can be ignored for the comparison. Those are contained in the new string resource \rsc{select.ignored}. \end{New} \begin{New}{gene} New resource \rsc{print.entry.types} introduced. This resource controls the entry types and the order in which they are printed. In fact the macro printing facility is obsolete with this new resource. \end{New} \begin{New}{gene} New resource \rsc{clear.ignored.words} introduced. In fact this is a function which deletes all ignored words. Thus it is possible to determine all ignored words at runtime--even the compiled in defaults. \end{New} \begin{Fix}{gene} Bug fixed: selection honours the resource \rsc{print.all.strings} now. \end{Fix} \begin{Update}{gene} Makefiles slightly improved. Less manual adaption. Installation of all library files -- even on Solaris. \end{Update} \begin{Fix}{gene} Name formatting omission fixed: Translation and length are taken into account correctly. The new name format sign * has been introduced to denote the inheritance of the translation from the calling format. \end{Fix} \begin{Update}{gene} Restriction relaxed. Now it is possible to declare up to MAXINT entry types and not only 4096. The \verb|Record| data structure and the associated macros have been modified slightly to accomplish this. \end{Update} \begin{Fix}{gene} Bug in the aux file selection mechanism fixed. This bug caused some cross referenced entries to be missing under special circumstances. \end{Fix} \begin{Fix}{gene} Bug in \File{key.c} fixed which caused a crash because an initialization was missing under certain circumstances. \end{Fix} \begin{New}{gene} Make target \File{libbib.a} added. This is known to work on UNIX. I would like to get feedback for other systems. \end{New} \begin{Fix}{gene} Minor bug in \File{names.c} fixed. \end{Fix} \begin{Fix}{gene} Minor bug in \File{print.c} fixed. \rsc{print.wide.equal} does not have exceptions any more. \end{Fix} \begin{Fix}{gene} Minor bug in \File{print.c} fixed. Deleted fields are treated better. \end{Fix} \begin{Fix}{gene} Bug in \File{database.c} fixed which caused macro expansion to fail under certain circumstances. \end{Fix} \begin{Update}{gene} \BibTcl: \verb|bibtool format| allows to use the full power of format specifications. \end{Update} \begin{New}{gene} \BibTcl: \verb|bibtool sprint| added which returns the formatted string representation of an entry. \end{New} \begin{Fix}{gene} \BibTcl: Bug in \verb|$rec set \$key ...| fixed. \end{Fix} \begin{Update}{gene} Minor changes in the C interface (Just wait for the compiler or linker to complain about different arguments:-). \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.41}{} \begin{New}{gene} New boolean resource \rsc{print.equal.right} which controls whether the = in normal entries is aligned right or left. \end{New} \begin{New}{gene} New boolean \rsc{resource print.wide.equal} which controlls whether the equal sign is surrounded by spaces even if the alignment forces a narrower layout. \end{New} \begin{New}{gene} New boolean resource \rsc{print.comma.at.end} which controlls whether the comma between fields is printed at the end or at the beginning of a field/value pair. \end{New} \begin{New}{gene} New boolean resource \rsc{print.deleted.entries} which controls the treatment of deleted entries. If this resource is true then delete entries are put as comments into the output. This is the old behavior and thus it is the default. \end{New} \begin{New}{gene} Pseudo field \rsc{sortkey} added. \end{New} \begin{New}{gene} Pseudo field \rsc{source} added which contains the filename the record has been read from or the empty string if this can not be determined. \end{New} \begin{Fix}{gene} Makefile adapted to meet the description. \end{Fix} \begin{New}{gene} configure creates \File{./config.h} aswell. \end{New} \begin{New}{gene} Strings can be either local to a database or global. The output of macros does include local macros only. This is a point of incompatibility with previous versions. \end{New} \begin{New}{gene} Massive extensions to \BibTcl. \end{New} \begin{Doc}{gene} Cleaning of the sources and massive addition of documentation. Now the documentation of the C functions is present. Thus it becomes possible to use the \BibTool{} routines to write C programs. \BibTcl{} is a first application of this technique. Nevertheless a few changes seem possible before things are cut in stone. \end{Doc} \begin{Doc}{gene} According to a suggestion by Oren Patashnik the term entry is used instead of record -- at least in the documentation. \end{Doc} \begin{Fix}{gene} Minor bug in \File{print.c} fixed which caused looping when small values for line length and alignment column was given. \end{Fix} \begin{Fix}{gene} Minor bugfix in \File{key.c}. The resource \rsc{crossref.limit} was off by 1. \end{Fix} \begin{New}{gene} Some additions have been made to support new features in the forthcoming \BibTeX{} 1.0. They do not really work right now but just restrict the accepted input files. \end{New} \begin{New}{gene} Flag \texttt{--with-kpathsea} added to configure. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.40}{} \begin{New}{gene} Sorting uses the new key instead of the old one as before. This has not been specified, but the new behaviour might be more intuitive. \end{New} \begin{Fix}{gene} \rsc{key.format=empty} fixed. \rsc{key.format} \rsc{short.need} and \rsc{long.need} are aliases for \rsc{new.short} and \rsc{new.long} resp. \end{Fix} \begin{Update}{gene} Some error messages slightly improved. \end{Update} \begin{Fix}{gene} Minor print bug fixed: additional commas appeared when the last field was deleted. \end{Fix} \begin{Doc}{gene} Typo in documentation: I had typed \rsc{preserve.key} instead of \rsc{preserve.keys}. Shame on me:-) Some additional examples in the documentation. \end{Doc} \begin{Update}{gene} Field deletetion completely covered by the rewriting mechanism. \rsc{delete.field} is kept for backward compatibility as an alias. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.39}{} \begin{Update}{gene} The default for the pattern in the select resource is now '.'. Thus it is easier to select entries with a given type. \end{Update} \begin{New}{gene} New resource \rsc{preserve.keys} introduced. If this resource is on then key generation touches only entries with empty keys. The keys of other entries are left unchanged. Initially this resource is off. \end{New} \begin{Update}{gene} The disambiguation now respects the order of the entries. Previously it used the reverse order which was contra-intuitive. \end{Update} \begin{Update}{gene} Formating names: Names connected by ~ or tight initials (A.U. Thor) are now treated better. \end{Update} \begin{Fix}{gene} Nasty little bug in the key specification parser fixed. This has (sometimes) let to a wrong evaluation of disjunctions. \end{Fix} \begin{Fix}{gene} Minor bug in verbose messages fixed. \end{Fix} \begin{New}{gene} AutoConf scripts added. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.38}{} \begin{New}{gene} Format specifier \%d enhanced. It can fail now if no number is found in the field. The minus sign means padding to a fixed length. The plus sign means not to fail but use 0. The post specifier can be used to select another but the first number. E.g. \%.2d means to use the second number. \end{New} \begin{New}{gene} Format specifier \%D introduced. It acts like \%d but does not truncate the number. Thus larger numbers are used completetly. \end{New} \begin{Fix}{gene} Bug fixed. If the key format failed then the key was left empty. Now the default key is used as written in the documentation. Somehow the bugfix for the select statement has not made it into the last release. Now it should be in. \end{Fix} \begin{Doc}{gene} Several mistakes in the documentation corrected. \end{Doc} \end{Release} % ===================================================================== \begin{Release}{2.37}{} \begin{New}{gene} kpathsea support for searching \BibTeX{} files added. \end{New} \begin{Fix}{gene} Bugs fixed: Searching/key generation combination and aux file evaluation. \end{Fix} \begin{New}{gene} The distribution is now availlable in two forms: as a gzipped tar file and as a zip archive. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.36}{} \begin{New}{gene} Added sample file for interfacing \BibTool{} with Tcl: \File{Tcl/bibtool.tcl}. \end{New} \begin{New}{gene} Added sample file for interfacing \BibTool{} with Perl: \File{Perl/bibtool.pl}. \end{New} \begin{Fix}{gene} Minor bug fix in string parsing routines. E.g. select from command line was not evaluated properly. \end{Fix} \begin{Fix}{gene} Minor bug fixed. \rsc{add.field} now works again as described in the documentation. \end{Fix} \begin{Fix}{gene} Minor bug fixed. Command line argument \Arg{-r} issued a warning when everything was ok. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.35}{} \begin{Update}{gene} Inheritance via crossref can be used to access fields in another entry when creating keys. E.g. this means that crossreferencing inproceedings can access the booktitle of the proceedings. The new resource \rsc{crossref.limit} restricts the number of crossrefs followed. E.g. 0 means do not follow crossrefs (as it has been in previous releases). The default is 32. \end{Update} \begin{New}{gene} New boolean resource \rsc{check.do.delete} introduced. If this resource is on then the double entries are not only preceeded by \#\#\# instead of @ but deleted completely. \end{New} \begin{New}{gene} New boolean resource \rsc{sort.macros} introduced. If this is on then the macro definitions are sorted alphabetically. Default: on \end{New} \begin{Update}{gene} The handling of comments has been changed completely. Comments are now attached to the preamble/string/normal entry following them. Especially during sorting the comments are rearranged as well. This seems useful to keep comments on macro definitions and the definitions together. The last comment always stays at the end. \end{Update} \begin{Fix}{gene} Minor bug fixed. The searching for \File{.bibtoolrsc} went wrong. \end{Fix} \begin{Fix}{gene} Minor bug fixed. \rsc{output.file} resource acted incorrect. \end{Fix} \begin{New}{gene} \rsc{print.all.strings} acts like described in the documentation. \end{New} \begin{Update}{gene} Resource arguments in the command line can have unbalanced braces in strings now. Still there is no escape character defined. \end{Update} \begin{Update}{gene} Internally \BibTool{} can handle more than one database simultaneously. This is needed for the SQL interface. Let's see how this can be used otherwise. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.34}{} \begin{Update}{gene} Default value of \rsc{key.expand.macros} changed to on. This seems to be a more sensible default value. (Possible incomatibility to old version) \end{Update} \begin{New}{gene} \rsc{new.format.type} introduced. This command can be used to specify formatting rules for names. It is used in conjunction with the \%p format specification which has been added. \end{New} \begin{New}{gene} The format specifiers for counting names/words/characters have been added. Those act as booleans which force backtracking if they fail. The qualifier \# is used to enable counting. \end{New} \begin{Update}{gene} When writing macro files undefined macros are written as \verb|_string| instead of \verb|@STRING|. Thus they are comments to \BibTeX{}. \end{Update} \begin{Update}{gene} The command line options \Arg{-x} and \Arg{-X} now also set \rsc{print.all.strings} to off. (This has no effect yet) \end{Update} \begin{Doc}{gene} The documentation has been updated. \end{Doc} \end{Release} % ===================================================================== \begin{Release}{2.33}{} \begin{New}{gene} Reference card added (prepared for A4 paper). \end{New} \begin{Fix}{gene} Bugfix in \File{rewrite.c}. \rsc{add.field} no longer crashes. \end{Fix} \begin{Update}{gene} Format specifiers \%n and \%N now also use the post argument. This argument is used to restrict the number of characters transferred. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.32}{} \begin{New}{gene} New resource \rsc{select.fields} introduced. This resource controlls which fields are considered when selecting with \Arg{-X}. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.31}{} \begin{Update}{gene} I have moved to a new job. My email address has been changed in all files (maybe I have missed some?). \end{Update} \begin{Fix}{gene} The resource \rsc{select.case.sensitive} behaved contra-intuitive. This has been fixed. This means that old scripts might need adaption. \end{Fix} \begin{Update}{gene} \rsc{select} and \rsc{rewrite.rule} can take several fields now. Thus you can specify several selections or rewrites more compact. \end{Update} \begin{Doc}{gene} The survey of related programs in the documentation has been enlarged. \end{Doc} \end{Release} % ===================================================================== \begin{Release}{2.30}{} \begin{Fix}{gene} Minor bugfix in \File{s\_parse.c}. Resource specifications in the command line may have let to an overflow of an array. This has been fixed. \end{Fix} \begin{New}{gene} New resource \rsc{print.parentheses} introduced. This resource allows the user to specify whether {} or () should be used to delimit each entry. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.29}{} \begin{Update}{gene} Support for compilation without the GNU Regular Expression Library improved. \end{Update} \begin{Update}{gene} The \verb|@comment| is really more liberal than I thought. This prefix is simply ignored (As I have read in the \BibTeX{} sources). This behaviour is now also performed by \BibTool{}. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.28}{} \begin{Update}{gene} Some additional updates for the new makefiles. \end{Update} \begin{Fix}{gene} Bugfix in \File{print.c} which let to additional strings after the regular end of an entry. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.27}{} \begin{Update}{gene} Reorganization of the files. Slight corrections of function protptypes in various files. Change of the \File{Makefile} to support Amiga SAS/C. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.26}{} \begin{Fix}{gene} Minor bug in \File{key.c} fixed. One step further to a 8-bit clean program. I wonder which 8-bit traps are still hidden in \BibTool. \end{Fix} \begin{Update}{gene} The \TeX{} macro mechnism has been enhanced to allow one to define single character macros. This means \rsc{tex.define} automatically makes a character active if it is encountered as macro name of a definition. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.25}{} \begin{Update}{gene} Finally all separators can be arbitrary strings. Only allowed characters are used (as it has been done in version 1.*). I hope this finally fixes the bug in key.c which I had troubles with in the previous versions. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.24}{} \begin{Doc}{gene} Documentation for regular expressions added. \end{Doc} \begin{New}{gene} Resources \rsc{select} and \rsc{select.case.sensitive} added. The selection allows to specify a regular expression for arbitrary fields. This subsumes the old \rsc{extract.regex} which is kept for backward compatibility. \end{New} \begin{Fix}{gene} A bugfix in 2.23 corrected. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.23}{} \begin{Update}{gene} Some minor modifications for DEC-Alpha. \end{Update} \begin{Update}{gene} Some minor modifications for the native HP C compiler. \end{Update} \begin{Fix}{gene} Some bugs in \File{key.c} fixed. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.22}{} \begin{Update}{gene} \BS par (double newlines) is preserved now. \rsc{parse.c} has been modified. The line breaking algorithm in \File{print.c} has been adapted. \end{Update} \begin{Fix}{gene} Allocation bug in \File{stack.c} fixed. \end{Fix} \begin{Fix}{gene} Bug in \File{expand.c} which added garbage to expanded strings. \end{Fix} \begin{Update}{gene} Some improvements for non-ANSI C compilers (I really don't know why I continue this). \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.21}{} \begin{New}{gene} Preserving of case of keys introduced. For this purpose the resource \rsc{preserve.key.case} has been introduced. The management of the list of old keys is done in \File{macros.c} mainly. Minor changes in \File{print.c} and \File{parse.c}. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.20}{} \begin{Fix}{gene} Minor bug fix in \rsc{sort.order}. \end{Fix} \begin{Update}{gene} Compression method changed to gzip. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.19}{} \begin{New}{gene} Key format specifiers t, w, W introduced. w, W, t and T take a post argument to limit the number of characters to use. \end{New} \begin{New}{gene} \rsc{sort.order} introduced to sort fields in an entry. \end{New} \begin{Update}{gene} Wrong mail addresses in many files corrected. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.18}{} \begin{Fix}{gene} Rewriting missed some multiply occurring patterns. (\File{rewrite.c}) \end{Fix} \begin{New}{gene} Resource \rsc{rewrite.limit} added. \end{New} \begin{Fix}{gene} Problem with recursive resources fixed. (\File{parse.c}) \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.17}{} \begin{Doc}{gene} The documentation is now compatible with \LaTeXe. \end{Doc} \end{Release} % ===================================================================== \begin{Release}{2.16}{} \begin{New}{gene} New resource \rsc{print.newline} introduced to control the number of empty lines between entries. \end{New} \begin{New}{gene} MSDOS support: Imitating emtex search path initialization as option. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.15}{} \begin{Fix}{gene} Some problems with 8-bit characters fixed. \end{Fix} \begin{New}{gene} String expansion before key generation added: \rsc{key.expand.macro} \end{New} \begin{Fix}{gene} Hashindex was computed wrong for some strings with ASCII values $>$ 127. \end{Fix} \begin{Update}{gene} Hashtable enlarged and new algorithm for hashindex \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.14}{} \begin{Fix}{gene} \rsc{delete.field} bug fixed. The deletion of the last field lead to the deletion of all fields. (\File{rewrite.c}) \end{Fix} \begin{Update}{gene} Comments added to \File{print.c}. \end{Update} \begin{New}{gene} Target zip in \File{Makefile}. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.13}{} \begin{New}{gene} Yet more modifications for the MSDOS port. What a brain-dead OS. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.12}{} \begin{Update}{gene} Version 2.12 of GNU regex library integrated. \end{Update} \begin{Update}{gene} \File{alloca.c} is no longer needed. \end{Update} \begin{Fix}{gene} Some improvements for the MSDOS port. \end{Fix} \begin{Fix}{gene} \File{aux.[ch]} renamed to \File{tex\_aux.[ch]} resp. \end{Fix} \begin{Fix}{gene} Resource search path seems to work now. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.11}{} \begin{Fix}{gene} Some typos fixed. \end{Fix} \begin{Update}{gene} Redefinition of entry types enabled. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.10}{} \begin{New}{gene} String/Macro expansion added: \rsc{expand.macros}. \end{New} \begin{Update}{gene} Case in-sensitive treatment of ignored words. \end{Update} \begin{Update}{gene} Some additional targets in \File{Makefile}. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.09}{} \begin{Update}{gene} \File{Makefile} enhanced. \end{Update} \begin{Update}{gene} Error/verbose/debug messages improved. \end{Update} \begin{Fix}{gene} Hell, I forgot to remove trace statements. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.08}{} \begin{Update}{gene} Comment parsing and printing improved. \end{Update} \begin{New}{gene} \rsc{symbol.type} introduced. \end{New} \begin{Update}{gene} Minor improvement of non-ANSI support. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.07}{} \begin{Update}{gene} Printing improved. Rewriting of macro names completed and documented. \end{Update} \begin{Fix}{gene} Truncating bug in \File{print.c} fixed. \end{Fix} \begin{Update}{gene} Minor improvement of non-ANSI support. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.06}{} \begin{New}{gene} UN*X man pages for \verb|sbuffer()|, \verb|pxfile()| \end{New} \begin{Update}{gene} Absolute path name use improved. \end{Update} \begin{Fix}{gene} Minor bug fixed. \end{Fix} \end{Release} % ===================================================================== \begin{Release}{2.05}{} \begin{New}{gene} Semantic checks with regular expressions. \end{New} \begin{Update}{gene} Crossref modification when key generation is enabled. \end{Update} \begin{Fix}{gene} Preference bug for search path building fixed. \end{Fix} \begin{Update}{gene} Rewriting enhanced. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.04}{} \begin{New}{gene} String parser introduced. Error checking/messages improved. \end{New} \begin{Update}{gene} Undocumented command line options changed. \end{Update} \begin{New}{gene} Command line specification of resources introduced. \end{New} \begin{Fix}{gene} Minor bug fixes. \end{Fix} \begin{Update}{gene} Code slightly reorganized. (I really found a static array) \end{Update} \begin{Update}{gene} Samples directory renamed to \File{Lib}. \end{Update} \end{Release} % ===================================================================== \begin{Release}{2.03}{} \begin{New}{gene} Field rewriting introduced. \end{New} \begin{Update}{gene} Resource \rsc{optimize} is obsolete. The functionality can be achieved by field rewriting. \end{Update} \begin{New}{gene} Resource search path introduced. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.02}{} \begin{Fix}{gene} Minor bug fixes. \end{Fix} \begin{Update}{gene} Static array in key generation routine made dynamic. There is still a limit which can be reached when a short \TeX{} macro expands into very long text. \end{Update} \begin{New}{gene} Checking double entries feature introduced. \end{New} \begin{New}{gene} Printing TABs can be emulated by SPACEs. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.01}{} \begin{Fix}{gene} Bug fixes. \end{Fix} \begin{New}{gene} Print representation for items introduced. \end{New} \begin{Update}{gene} Distribution improved. \end{Update} \begin{New}{gene} Resource samples added. \end{New} \end{Release} % ===================================================================== \begin{Release}{2.0}{} \begin{New}{gene} Major revision. \end{New} \begin{New}{gene} Sorting integrated. \end{New} \begin{New}{gene} Resources introduced. \end{New} \begin{Update}{gene} Several command line options deleted. \end{Update} \begin{Update}{gene} Key formatting improved. \end{Update} \begin{Doc}{gene} Draft Documentation. \end{Doc} \end{Release} % ===================================================================== \begin{Release}{1.7}{} \item[] \end{Release} \end{multicols} \end{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Local Variables: % mode: latex % TeX-master: nil % End: BibTool/ToDo0000644000175100017510000001326012536345002011622 0ustar genegene##============================================================================= ## ## This file is part of BibTool. ## It is distributed under the GNU General Public License. ## See the file COPYING for details. ## ## (c) 1996-2015 Gerd Neugebauer ## ## Net: gene@gerd-neugebauer.de ## ##***************************************************************************** This file contains ideas for improvements. Most of the items are mere key words and may not be meaningful for others. I try to keep the items in a order form highest to lowest priority. However, I change the order from time to time and hopefully items will disappear at some time. General ideas: * Use Unicode UTF8 as internal character set. This goes beyond BibTeX and brings in a new quality. This requires that reading and writing are aware of the character encoding. Additionally the regex processing needs to be replaced by something which is Unicode-aware. ICU seems to be the way to go. But it appears to be a pretty large beast. * Make a C library of routines for manipulating BibTeX files. (partially done. The main emphasis went into the documentation. Additional cleaning needed) - Use the lib and provide a interface to various programming languages. The first candidate would be C. Other candidates are C++, Tcl, Perl, Guile. - Use the lib and provide an SQL interface (see below). - Use the lib to write a better BibTeX. * Add a SQL like extraction language (partially exists). Maybe this is the time to completely redesign the resource language. I think I will make a major revision or a seperate program/library for this. Special ideas: * Provide a better installation routine. Especially for BibTcl a wish script might be the best solution since wish has to be installed before BibTcl can be made. * The different keys: Sortkey/OldKey deserve a clearer handling. Maybe some bugs are hidden here. * Maybe an index/several indices should be used to speed up access to records. Maybe a real database engine should be used for the underlying mechanism. * Support for the extended key notation file::key. This is said to be used in BibTeX1.0. * Support the special fields @ALIAS and @MODIFY as described by Oren Patashnik in TUGboat. (partially done) Each function has to be checked to decide if a refinement of the specification is necessary * Implement a garbage collector for the symbol table to avoid memory leaks when used from C/C++/Tcl/Perl/... * An escape character in strings might be missing. * Integrate field rewriting into the key generation algorithm. Allow arbitrary fields to be constructed like keys. Maybe this is a step towards a general manipulation language. I should keep this in mind for major revision 3. (The reverse is done. Key formats are evaluated when rewriting) * General formatting language (Maybe a replacement for BibTeX) Other applications: extract all keys, prettyprint entries in pure ASCII (HTML), etc. The main problem is to make a decision for the scripting language. I think I should use something existing and not roll a new one. (Tcl, Perl, or Guile are likely candidates) * Use a tree representation in field rewriting instead of parsing and evaluating the format each time (speed issue). * Do a better job when sorting. Especially for international bibliographies the sorting may not be adequate. Learn something from xindy? * Analyze bst files to find record types and entries used. (partially exists but is not integrated yet) * Provide a specification for the statistics function. Maybe SQL serves for this purpose. * Use the kpathsea library to find files. It has been done for Unix-like operating systems. For others it's still missing. * Selection of items according to regexp match on fields. This has to be generalized to allow full power of a first order language. * Make the program 16-bit clean. This means UniCode! * Eliminate compiled in defaults completely. Use a library directory to load initializations. * Integrate add/delete.field into the rewriting mechanism. * Automatic string detection. The reverse of string expansion. Replace common values by new strings. This can partially be done with field rewriting! * Respect crossref at selection * Support \cite in fields. * Documentation: improve tutorial part. (Maybe a book?) * Documentation in texinfo format? * Documentation in HTML format? * UN*X man pages? *** Write a graphical front end for BibTool - Maybe not a simple task. BibTool is already too powerful. (first experiments are not very promising) *** Write a replacement for BibTeX :-) Maybe I will wait until BibTeX 1.0 is out. - Better styles in a readable programming language. This is a major problem. Which language should I use? I am working towards making a library. Thus it should be easy to integrate BibTool into any language. - Object oriented approach. e.g. for proceedings containing articles. @proceeding{abc, editor = "...", booktitle = "...", title = "...", @inprocedings{1, author = "...", title = "..." } } - Drop limitations. E.g. - size of a field. - order of crossreferenced records - Support multi-language bibliographies. - Backward compatibility: It should be possible to use the new program as a replacement for the existing BibTeX without modification of the BibTeX database. The styles should be usable or an automatic translation into a new format should be provided. If you have read until here and you want to take one of the tasks then contact me. Gerd Neugebauer gene@gerd-neugebauer.de BibTool/THANKS0000644000175100017510000000356712646421320011756 0ustar genegene##============================================================================= ## ## This file is part of BibTool. ## It is distributed under the GNU General Public License. ## See the file COPYING for details. ## ## (c) 1996-2016 Gerd Neugebauer ## ## Net: gene@gerd-neugebauer.de ## ##***************************************************************************** BibTool would not exist in its current form without the help, bug reports and suggestions of several people. Thank you very much to all of them. Among others I have to mention the following. I have to apologize that this list is by far not complete since I am sometimes too lazy to add someone here. Josef Spangler josef.spangler@rz.uni-regensburg.de Jongwon Kim jwkim@asrispmp1.snu.ac.kr Pascal Molli Pascal.Molli@loria.fr Joerg Schierstein josch@intellektik.informatik.th-darmstadt.de Stephane Laveau laveau@corse.inria.fr Volker Kuhlmann kuhlmav@elec.canterbury.ac.nz Eric Garneau garneau@iro.umontral.ca Bjorn Victor Bjorn.Victor@DoCS.UU.SE Andreas Scherer SCHERER@genesis.informatik.rwth-aachen.de Gerhard Buntrock bunt@informatik.uni-wuerzburg.de Karl Dietrich karl@vwl.uni-hannover.de Hossein Saiedian hossein@csalpha.unomaha.edu A.L.S. Corner corner@vax.ox.ac.uk Michael S. Kluskens kluskens@crystal.nrl.navy.mil Stuart Yeates stuart@cosc.canterbury.ac.nz Stefan Becuwe stefan.becuwe@ua.ac.be Thomas Worsch worsch@ira.uka.de Franz Fischer Franz.Fischer@lpr.e-technik.tu-muenchen.de Uwe Nestmann Uwe.Nestmann@inria.fr Ronald Greenberg rig.math.luc.edu Jan Braun Jan.Braun.tu-bs.de Dirk Herrmann dirk@ida.ing.tu-bs.de Ryszard Tanas tanas@zon10.physd.amu.edu.pl Naftali Schwartz nschwart@slinky.cs.nyu.edu Patrice Dumas dumas@centre-cired.fr Martin Szummer szummer@media.mit.edu John Owens jowens@ece.ucdavis.edu Jerome Benoit calculus@rezozer.net Alexander Russell acr@cse.uconn.edu BibTool/pxfile.man0000644000175100017510000000500510562442115013014 0ustar genegene.TH pxfile 3 local .SH NAME pxfile \- Extended file opening with search path and optional extensions. .SH SYNOPSIS .nf .B #include "pxfile.h" .B FILE* px_fopen(filename,mode,pattern,path,show) .B char * filename; .B char * mode; .B char ** pattern; .B char ** path; .B int (*show)(); .B char **px_s2p(specification,seperator) .B char *specification; .B int seperator; .fi .SH DESCRIPTION The extended file opening routine allows to open a file like .B fopen(3) . The file is searched on a path and additional modifications of the file name are possible. E.g. the addion of an extension or prepending a fixed prefix is posible. .BR px_fopen () opens a file named .I filename with the mode .I mode which is the same as the mode used by .BR fopen (3). .I path is a NULL terminated array of strings indicating the possible directories to search for the file. A value of .I NULL indicates that only the current directory should be examined. .BR px_s2p () can be used to allocate and fill a path array form a simple string specification. .I pattern is a NULL terminated array of format specifications to be used with .BR fprintf (3). Two strings are indicated with the special '%s'. The first '%s' is replaced by the directory name. The second '%s' is replaced by the file name given. A value of .I NULL is the same as .nf { "%s/%s", NULL } .fi The following example value of .I pattern shows how default extensions can be tried. First the pure file name is tried. Afterwards the extensions .B .tex and .B .TeX are tried. .nf { "%s/%s", "%s/%s.tex", "%s/%s.TeX", NULL } .fi .I show is a pointer to a function. This function is called before an attempt is made to open a file. The argument of the function is the complete file name as string. The open is tried only if .I show returns an integer different from 0. This function can be used to display the file names before trying to open. A value of .I NULL can be used to indicate that no such function should be used. .BR px_s2p () constructs a .I pattern for .BR px_fopen () from a .I specification. Memory is allocated to store the array and the strings contained. .I specification is a strings where the different directories are separated by the character .I seperator. If not enough memory is available .I NULL is returned. The memory allocated consists of one block which can be freed with .BR free (3). .SH FILES pxfile.h .SH SEE ALSO .BR fopen (3), .BR fprintf (3), .BR free (3) .SH DIAGNOSTICS NULL is returned to indicate failure. .SH BUGS Mainly UN*X type file names are supported. BibTool/sbuffer.man0000644000175100017510000000437110562442117013170 0ustar genegene.TH StringBuffer 3 local .SH NAME StringBuffer \- Handle strings like files .SH SYNOPSIS .nf .B #include "sbuffer.h" .B StringBuffer* sbopen() .B int sbclose(sb) .B StringBuffer* sb; .B int sbputs(string,sb) .B char* string; .B StringBuffer* sb; .B int sbputc(c,sb) .B int c; .B StringBuffer* sb; .B int sbputchar(c,sb) .B int c; .B StringBuffer* sb; .B char* sbflush(sb) .B StringBuffer* sb; .B int sbtell(sb) .B StringBuffer* sb; .B int sbrewind(sb) .B StringBuffer* sb; .B int sbseek(sb,pos) .B StringBuffer* sb; .B int pos; .fi .SH DESCRIPTION The string buffer routines are a means to use strings like files. The routines manage the allocation and freeing of memory internally. .B sbopen() returns a new string buffer. Memory is allocated to keep the informations required. .B sbclose() frees the memory allocated for a string buffer. Any access to a part of the string buffer is not save after this call. .B sbputs() put a string into the string buffer. The string is appended at the end of existing contents. 0 is returned upon success. .B sbputc() put a character into the string buffer. The character is appended at the end of existing contents. 0 is returned upon success. This is a function. A macro with the same functionality is provided by .B sbputchar() .B sbputchar() put a character into the string buffer. This is a macro with the same functionality as .B sbputc() .B sbtell() find the current position of the string buffer for later use with .B sbseek() .B sbseek() set the writing position of the string buffer to the given value. If value points beyond the current string size non null is returned. .B sbrewind() reset the writing position to the beginning of the string buffer. .B sbflush() close the string component of the string buffer and return a pointer to a string containing the contents of the string buffer. The writing position is not changed. Thus following calls to .B sbputs() or .B sbputc() continue adding characters. The string may not be properly terminated after additional writing operations. .SH FILES sbuffer.h .SH SEE ALSO .BR fopen (3), .BR fclose (3), .BR fputs (3), .BR fputc (3), ... .SH DIAGNOSTICS Usually 0 is returned to indicate success. .SH BUGS Missing a .B printf() variant for string buffer. Horrible documentation. BibTool/Perl/bibtool.pl0000755000175100017510000000424012646461405013734 0ustar genegene#!/usr/local/bin/perl ##***************************************************************************** ## ## This file is part of BibTool. ## It is distributed under the GNU General Public License. ## See the file COPYING for details. ## ## (c) 1996-2016 Gerd Neugebauer ## ## Net: gene@gerd-neugebauer.de ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ## ##***************************************************************************** # # This sample file shows how bibtool can be interfaced with Perl. # BibTool is assumed to be on the search path for executables. # BibTool is called with the appropriate parameters. In this examples # it is used only for normalization of the BibTeX database. # Afterwards it is rather simple for Perl to parse the result. # $file=$ARGV[0]; # take the first argument as file name open(FD,"bibtool -q -- expand.macros=on -- pass.comments=off -- print.line.length=999999 -- print.indent=0 -- print.align=0 $file |"); $bibtool_is_in_record = 0; while() { if (/^\@STRING/o) { } elsif (/^\@PREAMBLE/o) { } elsif (/^\@COMMENT/o) { } elsif ($bibtool_is_in_record == 0 && /^@([a-zA-Z]*){[ \t]*(.*),/o) { $type = $1; $key = $2; printf("type: %s\nkey: %s\n",$type,$key); $bibtool_is_in_record = 1; } elsif ($bibtool_is_in_record == 1 && /([a-zA-Z]*)=(.*)$/o) { $item = $1; $value = $2; printf("entry: %s\nvalue: %s\n",$item,$value); } elsif ($bibtool_is_in_record == 1 && /^}/o) { printf("END_OF_RECORD\n"); $bibtool_is_in_record = 0; } } close(FD); BibTool/Tcl/bibtool.tcl0000755000175100017510000000431712646461647013740 0ustar genegene#!/usr/local/bin/tclsh ##***************************************************************************** ## ## This file is part of BibTool. ## It is distributed under the GNU General Public License. ## See the file COPYING for details. ## ## (c) 1996-1997 Gerd Neugebauer ## ## Net: gene@gerd-neugebauer.de ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2, or (at your option) ## any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ## ##***************************************************************************** # # This sample file shows how bibtool can be interfaced with Tcl(/Tk). # BibTool is assumed to be on the search path for executables. # BibTool is called with the appropriate parameters. In this examples # it is used only for normalization of the BibTeX database. # Afterwards it is rather simple for Tcl to parse the result. # # take the first argument as file name set file [lindex $argv 0] set FD [open "|bibtool -q -- pass.comments=off -- print.line.length=999999 -- print.indent=0 -- print.align=0 $file" r] set bibtool_is_in_record 0 while { [gets $FD line] >= 0 } { if {[regexp {^\@STRING} $line]} { } elseif {[regexp {^\@PREAMBLE} $line]} { } elseif {[regexp {^\@COMMENT} $line]} { } elseif { !$bibtool_is_in_record && [regexp -nocase {^\@([a-z]*)\{[ ]*(.*),} $line all type key]} { puts "type: $type\nkey: $key" set bibtool_is_in_record 1 } elseif {$bibtool_is_in_record && [regexp -nocase {([a-z]*)=(.*)} $line all item value]} { regsub {,$} $value {} value puts "entry: $item\nvalue: $value" } elseif {$bibtool_is_in_record && $line=="\}"} { puts END_OF_RECORD set bibtool_is_in_record 0 } } close $FD BibTool/main.c0000644000175100017510000011215012646457515012137 0ustar genegene/*** main.c ******************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** >>> See the file doc/c_lib.tex for a printed documentation of the ** >>> main parts of the C source. ** **----------------------------------------------------------------------------- ** Description: ** This is the \BibTool{} main module. It contains the |main()| ** function which evaluates the command line arguments and ** proceeds accordingly. This means that usually resource files ** and \BibTeX{} files are read and one or more \BibTeX{} files ** are written. ** ** This file makes use of the \BibTool{} C library but is not ** part of it. For this purpose it has to provide certain ** functions which are expected by the library. These functions ** are: ** \begin{quote} ** \texttt{save\_input\_file()}\\ ** \texttt{save\_macro\_file()}\\ ** \texttt{save\_output\_file()}\\ ** \end{quote} ** The arguments and the expected behavior of these functions is ** described below. ** ** If you are trying to understand the implementation of ** \BibTool{} the file |resource.h| plays a central ** r\^ole. Consult the description of this file for further ** details. ** ** If you are trying to write your own program to manipulate ** \BibTeX{} files then this file can serve as a starting point. ** But you should keep in mind that this file has grown over ** several years and it contains the full complexity of the ** \BibTool{} program logic. Thus you can reduce this file ** drastically if you start playing around with the \BibTool{} C ** library. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBKPATHSEA #ifdef __STDC__ #define HAVE_PROTOTYPES #endif #include #endif #include "config.h" /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int main _ARG((int argc,char *argv[])); /* main.c */ static int dbl_check _ARG((DB db,Record rec)); /* main.c */ static int do_keys _ARG((DB db,Record rec)); /* main.c */ static int do_no_keys _ARG((DB db,Record rec)); /* main.c */ static int rec_gt _ARG((Record r1,Record r2)); /* main.c */ static int rec_gt_cased _ARG((Record r1,Record r2));/* main.c */ static int rec_lt _ARG((Record r1,Record r2)); /* main.c */ static int rec_lt_cased _ARG((Record r1,Record r2));/* main.c */ static int update_crossref _ARG((DB db,Record rec));/* main.c */ static void usage _ARG((int fullp)); /* main.c */ void save_input_file _ARG((char *file)); /* main.c */ void save_macro_file _ARG((char *file)); /* main.c */ void save_output_file _ARG((char * file)); /* main.c */ /*****************************************************************************/ /* External Programs and Variables */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ #ifndef __STDC__ #ifndef HAVE_GETENV char * getenv _ARG((char *name)); /* main.c */ /*----------------------------------------------------------------------------- ** Dummy funtion returning NULL to indicate failure. **___________________________________________________ */ char * getenv(name) /* */ char *name; /* */ { return (char*)NULL; /* */ } /*------------------------*/ #endif #endif #ifndef OptionLeadingCharacter #define OptionLeadingCharacter '-' #endif static char *use[] = { "bibtool [options] [%co outfile] [[%ci] infile] ...\n", "\n\tOptions:\n", "\t%cA\t\tKind of disambiguating key strings: =0|a|A\n", "\t%cc\t\tInclude crossreferenced entries into the output (toggle)\n", "\t%cd\t\tCheck double entries (toggle)\n", "\t%cf \tKey generation enabled (formated key)\n", "\t%cF\t\tKey generation enabled with formated key\n", "\t%ch\t\tPrint this help info and exit\n", "\t[%ci] infile\tSpecify input file. If %ci omitted it may not start\n", "\t\t\twith a %c. If absent stdin is taken to read from.\n", "\t\t\tMultiple input files may be given.\n", "\t%ck\t\tKey generation enabled.\n", "\t%cK\t\tKey generation enabled (long key).\n", "\t%cm macfile\tDump macros to macfile. - is stdout\n", "\t%cM macfile\tDump used macros to macfile. - is stdout\n", "\t%co outfile\tSpecify output file as next argument\n", "\t\t\tIf absent stdout is taken to write to.\n", "\t%cq\t\tQuiet mode. No warnings.\n", "\t%cr resource\tLoad resource file (several are possible).\n", "\t%cR\t\tLoad default resource file here.\n", "\t%cs\t\tSort.\n", "\t%cS\t\tSort reverse.\n", "\t%cv\t\tEnable verbose mode.\n", "\t%cV\t\tPrint version and exit.\n", "\t%cx file\t\tExtract from aux file.\n", "\t%cX \tExtract regular expression.\n", "\t%c- \tEvaluate one resource command .\n", "\t%c@\t\tPrint statistics (short).\n", "\t%c#\t\tPrint statistics.\n", #ifdef SYMBOL_DUMP "\t%c$\t\tSymbol table output (debugging only)\n", #endif 0L, "Copyright (C) 2016 Gerd Neugebauer", "gene@gerd-neugebauer.de" }; /*----------------------------------------------------------------------------- ** Function: usage() ** Purpose: Print the version number, a copyright notice, and ** a short description of the command line options on the ** |stderr| stream. ** In addition certain configuration options are ** printed. If the argument is |FALSE| then only the ** copyright and the version number are displayed. ** Arguments: ** fullp Boolean. If |FALSE| only the version is displayed. ** Returns: nothing **___________________________________________________ */ static void usage(fullp) /* */ int fullp; /* */ { static char *comma = ", "; /* */ char *sep = " "; /* */ POSSIBLY_UNUSED(comma); /* */ POSSIBLY_UNUSED(sep); /* */ /* */ show_version(); /* */ /* */ if ( fullp ) /* */ { register char **cpp; /* */ for ( cpp = use; *cpp; cpp++ ) /* */ { ErrPrintF2(*cpp, /* */ OptionLeadingCharacter, /* */ OptionLeadingCharacter); /* */ } /* */ ErrPrint("\n"); /* */ } /* */ /* */ ErrPrintF("Library path: %s", /* */ (rsc_v_rsc == NULL /* */ ? "none" /* */ : (char*)rsc_v_rsc)); /* */ /* */ ErrPrint("\nSpecial configuration options:"); /* */ #define SPECIAL_OPTIONS " none" #ifdef HAVE_LIBKPATHSEA ErrPrintF("%skpathsea",sep); /* */ sep = comma; /* */ #undef SPECIAL_OPTIONS #define SPECIAL_OPTIONS "" #endif #ifndef REGEX ErrPrintF("%sNO regex",sep); /* */ sep = comma; /* */ #undef SPECIAL_OPTIONS #define SPECIAL_OPTIONS "" #endif #ifdef EMTEX_LIKE_PATH ErrPrintF("%semTeX like path",sep); /* */ #undef SPECIAL_OPTIONS #define SPECIAL_OPTIONS "" #endif ErrPrintF("%s\n",SPECIAL_OPTIONS); /* */ } /*------------------------*/ #define UnknownWarning(X) WARNING2("Unknown flag ignored: ",X) #define NoSFileWarning WARNING("Missing select option. Flag ignored.") #define NoFileError(X) WARNING3("File ",X," not found.") #define MissingPattern WARNING("Missing pattern.") #define MissingResource WARNING("Missing resource.") #define NoRscError(X) WARNING3("Resource file ",X," not found.") /*****************************************************************************/ /*** Input File Pipe Section ***/ /*****************************************************************************/ #define InputFilePipeIncrement 8 static char **input_files; static int input_file_size = 0; static int input_file_ptr = 0; #define InputPipeIsFull (input_file_ptr >= input_file_size) #define InputPipeIsEmpty (input_file_ptr == 0) #define PushToInputPipe(FILE) input_files[input_file_ptr++] = FILE #define ForAllInputFiles(FILE) for (FILE=input_files; \ FILE<&input_files[input_file_ptr]; \ FILE++) /*----------------------------------------------------------------------------- ** Function: save_input_file() ** Purpose: The input file pipe is a dynamic array of strings. ** This fifo stack is used to store the input \BibTeX{} ** files to be processed by \BibTool. ** ** This function is called to push an string into the pipe. ** If necessary the array has to be allocated or enlarged. ** This is done in larger junks to avoid lots of calls to ** |realloc()|. ** Arguments: ** file File name to save. ** Returns: nothing **___________________________________________________ */ void save_input_file(file) /* */ char *file; /* */ { /* */ if (file == NULL) /* */ { WARNING("Missing input file name. Flag ignored.");/* */ return; /* */ } /* */ if (*file == '-' && file[1] == '\0') /* */ { file = NULL; } /* */ /* */ if (InputPipeIsFull) /* No space left? */ { input_file_size += InputFilePipeIncrement; /* */ /* */ if (InputPipeIsEmpty /* Try to enlarge array */ ? NULL==(input_files= /* */ (char**)malloc(sizeof(char*) /* */ *(size_t)input_file_size))/* */ : NULL==(input_files= /* */ (char**)realloc((char*)input_files,/* */ sizeof(char*) /* */ *(size_t)input_file_size))/* */ ) /* */ { OUT_OF_MEMORY("input file pipe."); } /* */ } /* */ PushToInputPipe(file); /* */ } /*------------------------*/ /*****************************************************************************/ /*** Output File Section ***/ /*****************************************************************************/ static char *output_file = NULL; /* */ /*----------------------------------------------------------------------------- ** Function: save_output_file() ** Purpose: Simply feed the output file name into the static variable. ** This function is useful since it can be called from rsc.c ** Arguments: ** file File name to save ** Returns: nothing **___________________________________________________ */ void save_output_file(file) /* */ char * file; /* */ { if ( output_file != NULL ) /* */ { WARNING2("Output file redefined: ",file); } /* */ output_file = file; /* */ } /*------------------------*/ /*****************************************************************************/ /*** Macro File Section ***/ /*****************************************************************************/ static char *macro_file = NULL; /* */ /*----------------------------------------------------------------------------- ** Function: save_macro_file() ** Purpose: Simply feed the macro file name into the static variable. ** This function is useful since it can be called from rsc.c ** Arguments: ** file File name to save ** Returns: nothing **___________________________________________________ */ void save_macro_file(file) /* */ char *file; /* */ { if ( macro_file != NULL ) /* */ { WARNING2("Macro file redefined: ",file); } /* */ macro_file = file; /* */ } /*------------------------*/ /*****************************************************************************/ /*** MAIN ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: keep_selected() ** Type: static int ** Purpose: Mark the record as deleted if it is not selected. ** ** Arguments: ** db the database ** rec the record ** Returns: FALSE **___________________________________________________ */ static int keep_selected(db, rec) /* */ DB db; /* */ Record rec; /* */ { /* */ if (!is_selected(db, rec)) /* */ { SetRecordDELETED(rec); } /* */ /* */ return FALSE; /* */ } /*------------------------*/ #ifdef UNUSED /*----------------------------------------------------------------------------- ** Function: keep_xref() ** Type: int ** Purpose: Undelete crossreferenced entries ** ** Arguments: ** db the database ** rec the record ** Returns: FALSE **___________________________________________________ */ int keep_xref(db,rec) /* */ DB db; /* */ Record rec; /* */ { /* */ if ( !RecordIsDELETED(rec) ) /* */ { String key; /* */ int count; /* */ /* */ for (count = rsc_xref_limit; /* Prevent infinite loop */ count >= 0; /* */ count--) /* */ { /* */ if ( (key = get_field(db,rec,sym_crossref)) == NULL )/* */ { return FALSE; } /* */ /* */ key = symbol(lower(expand_rhs(key, /* */ sym_empty, /* */ sym_empty, /* */ db))); /* */ if ( (rec=db_search(db,key)) == RecordNULL ) /* */ { ErrPrintF("*** BibTool: Crossref `%s' not found.\n",key);/* */ return FALSE; /* */ } /* */ /* */ if (!RecordIsDELETED(rec)) { return FALSE; } /* */ ClearRecordDELETED(rec); /* */ } /* */ /* */ ErrPrintF("*** BibTool: Crossref limit exceeded; `%s' possibly looped.\n", key); /* */ } /* */ return FALSE; /* */ } /*------------------------*/ #endif #define Toggle(X) X = !(X) /*----------------------------------------------------------------------------- ** Function: main() ** Purpose: This is the main function which is automatically ** called when the program is started. This function ** contains the overall program logic. It has to perform ** the appropriate initializations, evaluate command line ** arguments, and run the main loop. ** Arguments: ** argc Number of arguments ** argv Array of arguments ** Returns: 0 upon success. Usually a failure raises an exception ** which leads to an |exit()|. Thus this function does ** not need to signal an error to the calling environment. **___________________________________________________ */ int main(argc,argv) /* */ int argc; /* Argument count */ char *argv[]; /* Argument values */ { DB the_db; /* The \BibTool{} program */ /* currently handles a */ /* single database at a */ /* time. The local */ /* variable |the_db| */ /* contains a reference to*/ /* this database. */ int i; /* */ FILE *file; /* */ int need_rsc = TRUE; /* */ int (*fct)(); /* Function pointer */ int c_len; /* */ int *c = NULL; /* */ /* */ init_error(stderr); /* */ init_bibtool(argv[0]); /* */ /* */ for ( i = 1; i < argc; i++ ) /* */ { char *ap; /* */ if ( *(ap=argv[i]) != OptionLeadingCharacter ) /* */ { save_input_file(argv[i]); /* */ } /* */ else /* */ { switch ( *++ap ) /* */ { case 'A': set_base((String)(ap+1)); break;/* disambiguation */ case 'c': Toggle(rsc_xref_select); break;/* include crossreferences*/ case 'd': Toggle(rsc_double_check); break;/* double entries */ #ifdef HAVE_LIBKPATHSEA case 'D': kpathsea_debug=atoi(++ap); break;/* kpathsea debugging */ #endif case 'f': add_format(argv[++i]); /* !!! no break !!! */ case 'F': rsc_make_key = TRUE; break; /* key generation */ case 'h': usage(TRUE); return 1; /* print help */ case 'i': save_input_file(argv[++i]); break;/* */ case 'K': add_format("long"); break; /* key generation */ case 'k': add_format("short"); break; /* key generation */ case 'M': /* print macro table */ case 'm': rsc_all_macs = (*ap=='m'); /* print macro table */ save_macro_file(argv[++i]); /* */ break; /* */ case 'o': /* output file */ if ( ++i < argc ) /* */ { save_output_file(argv[i]); } /* */ else /* */ { WARNING("Missing output file name"); } /* */ break; /* */ case 'q': Toggle(rsc_quiet); break; /* quiet */ case 'r': /* resource file */ if ( ++i < argc && load_rsc((String)(argv[i])) )/* */ { need_rsc = FALSE; } /* */ else /* */ { NoRscError(argv[i]); } /* */ break; /* */ case 'R': need_rsc |= !search_rsc();break; /* default resource file */ case 's': Toggle(rsc_sort); break; /* sort */ case 'S': /* */ Toggle(rsc_sort); /* */ Toggle(rsc_sort_reverse); /* */ break; /* sort */ case 'v': Toggle(rsc_verbose); break; /* verbose */ case 'V': usage(FALSE); return 1; /* version */ case 'x': /* extract */ rsc_all_macs = FALSE; /* */ if ( ++i < argc ) /* */ { read_aux((String)(argv[i]), /* */ save_input_file, /* */ *++ap=='v'); /* */ } /* */ else /* */ { NoSFileWarning; } /* */ break; /* */ case 'X': /* extract pattern */ rsc_all_macs = FALSE; /* */ if ( ++i < argc ) { save_regex((String)argv[i]); }/* */ else { MissingPattern; } /* */ break; /* */ case '#': Toggle(rsc_cnt_all); break; /* print full statistics */ case '@': Toggle(rsc_cnt_used); break; /* print short statistics */ case '-': /* extended command */ if ( *++ap ) { (void)use_rsc((String)ap); }/* */ else if ( ++i 0 ) /* */ { ErrPrintF3("--- %-15s %5d read %5d written\n",/* */ get_entry_type(i), /* */ c[i], /* */ cnt[i]); /* */ } /* */ } /* */ free(c); /* */ } /* */ /* */ #ifdef SYMBOL_DUMP if ( rsc_dump_symbols ) sym_dump(); /* Write symbols. */ #endif /* */ #ifdef FREE_MEMORY free_db(the_db); /* */ the_db = NULL; /* */ sym_gc(); /* */ #ifdef SYMBOL_DUMP sym_dump(); /* */ #endif #endif return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rec_gt() ** Purpose: ** ** ** Arguments: ** r1 ** r2 ** Returns: **___________________________________________________ */ static int rec_gt(r1, r2) /* */ Record r1; /* */ Record r2; /* */ { return (strcmp((char*)RecordSortkey(r1), /* */ (char*)RecordSortkey(r2)) < 0); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rec_lt() ** Purpose: ** ** ** Arguments: ** r1 ** r2 ** Returns: **___________________________________________________ */ static int rec_lt(r1, r2) /* */ Record r1; /* */ Record r2; /* */ { return (strcmp((char*)RecordSortkey(r1), /* */ (char*)RecordSortkey(r2)) > 0); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rec_gt_cased() ** Type: static int ** Purpose: ** ** Arguments: ** r1 ** r2 ** Returns: **___________________________________________________ */ static int rec_gt_cased(r1, r2) /* */ Record r1; /* */ Record r2; /* */ { return (strcmp((char*)get_key_name(RecordSortkey(r1)),/* */ (char*)get_key_name(RecordSortkey(r2))) < 0);/* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rec_lt_cased() ** Type: static int ** Purpose: ** ** Arguments: ** r1 ** r2 ** Returns: **___________________________________________________ */ static int rec_lt_cased(r1, r2) /* */ Record r1; /* */ Record r2; /* */ { return (strcmp((char*)get_key_name(RecordSortkey(r1)),/* */ (char*)get_key_name(RecordSortkey(r2))) > 0);/* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: do_keys() ** Purpose: ** ** ** Arguments: ** rec ** Returns: **___________________________________________________ */ static int do_keys(db, rec) /* */ DB db; /* */ Record rec; /* */ { /* */ rewrite_record(db,rec); /* */ sort_record(rec); /* */ make_key(db,rec); /* */ if ( rsc_sort || rsc_double_check ) /* */ { make_sort_key(db,rec); } /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: do_no_keys() ** Purpose: ** ** ** Arguments: ** rec ** Returns: **___________________________________________________ */ static int do_no_keys(db, rec) /* */ DB db; /* */ Record rec; /* */ { /* */ rewrite_record(db,rec); /* */ sort_record(rec); /* */ mark_key(db,rec); /* */ if ( rsc_sort || rsc_double_check ) /* */ { make_sort_key(db,rec); } /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: update_crossref() ** Purpose: ** ** ** Arguments: ** rec ** first_rec ** Returns: nothing **___________________________________________________ */ static int update_crossref(db, rec) /* */ DB db; /* */ Record rec; /* */ { register String *hp; /* */ register int i; /* */ String s, t; /* */ /* */ if ( !RecordIsXREF(rec) ) return 0; /* */ /* */ for (i = RecordFree(rec), hp = RecordHeap(rec); /* search crossref field */ i > 0 && *hp != sym_crossref; /* */ i -= 2, hp += 2) /* */ { } /* */ if ( i <= 0 ) /* */ { DebugPrint1("*** No crossref found."); /* */ return 0; /* */ } /* */ /* */ t = *++hp; t++; /* */ (void)sp_open(t); /* Try to extract */ if ( (s = SParseSymbol(&t)) == StringNULL ) /* the crossref as symbol*/ { return 0; } /* */ /* */ if ( (s = db_new_key(db,s)) == StringNULL ) /* */ { ERROR2("Crossref not found: ",(char*)s); /* */ return 0; /* */ } /* */ if (rsc_key_case) { s = get_key_name(s); } /* */ if ( (t=(String)malloc(strlen((char*)s)+3))==(String)NULL )/* get temp mem */ { OUT_OF_MEMORY("update_crossref()"); } /* */ /* */ (void)sprintf((char*)t,(**hp=='"'?"\"%s\"":"{%s}"),s);/* make new crossref */ *hp = symbol(t); /* store new crossref */ free(t); /* free temp memory */ return 0; /* */ } /*------------------------*/ #define equal_records(R1,R2) RecordSortkey(R1) == RecordSortkey(R2) /*----------------------------------------------------------------------------- ** Function: dbl_check() ** Purpose: ** ** ** Arguments: ** rec ** Returns: **___________________________________________________ */ static int dbl_check(db, rec) /* */ DB db; /* */ Record rec; /* */ { /* */ if ( PrevRecord(rec) != RecordNULL /* */ && equal_records(PrevRecord(rec),rec) ) /* */ { /* */ if ( !rsc_quiet ) /* */ { String k1 = *RecordHeap(rec); /* */ String k2 = *RecordHeap(PrevRecord(rec)); /* */ ErrPrint("*** BibTool WARNING: Possible double entries discovered: \n***\t"); if ( k1 == NULL ) k1 = (String) ""; /* */ if ( k2 == NULL ) k2 = (String) ""; /* */ ErrPrint((char*)k2); /* */ ErrPrint(" =?= "); /* */ ErrPrint((char*)k1); /* */ ErrPrint("\n***\t"); /* */ ErrPrint((char*)RecordSortkey(rec)); /* */ ErrPrint("\n"); /* */ } /* */ if (rsc_del_dbl) /* */ { delete_record(db,rec); } /* */ else /* */ { SetRecordDELETED(rec); } /* */ } /* */ /* */ return 0; /* */ } /*------------------------*/ #ifdef DEBUG /*----------------------------------------------------------------------------- ** Function*: printchar() ** Purpose: For debugging of regex.c ** Arguments: ** c Character to print. ** Returns: nothing **___________________________________________________ */ void printchar(c) /* */ char c; /* */ { ErrC(c); /* */ } /*------------------------*/ #endif BibTool/crossref.c0000644000175100017510000001115612646453773013047 0ustar genegene/*** crossref.c *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 2007-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions to expand crossref entries. ** ******************************************************************************/ #include #include #include #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int expand_crossref _ARG((DB db,Record rec)); /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: expand_crossref() ** Purpose: Expand all items inherited via a crossref. ** Arguments: ** db Database containing the entries. ** rec The record to expand ** Returns: FALSE **___________________________________________________ */ int expand_crossref(db,rec) /* */ DB db; /* */ Record rec; /* */ { register String *hp; /* */ register int i; /* */ String t, s; /* */ Record r = rec; /* */ int limit = rsc_xref_limit; /* */ /* */ DebugPrint1("expand_crossref"); /* */ /* */ while ( RecordIsXREF(r) && limit-- >= 0 ) /* */ { /* */ for ( i = RecordFree(r), hp = RecordHeap(r); /* search crossref field */ i > 0 && *hp != sym_crossref; /* */ i -= 2, hp += 2 ) /* */ { } /* */ if (i <= 0) /* */ { DebugPrint1("*** No crossref found."); /* */ return FALSE; /* */ } /* */ if (rec == r) { *hp = NULL; } /* Delete the first xref */ t = *++hp; /* */ t++; /* */ (void)sp_open(t); /* Try to extract */ if ( (s = SParseSymbol(&t)) == StringNULL ) /* the crossref as symbol*/ { return FALSE; } /* */ /* */ if ( (r = db_find(db,s)) == (Record)NULL ) /* */ { ERROR2("Crossref entry not found: ",(char*)s);/* */ return FALSE; /* */ } /* */ /* */ for (i = RecordFree(r), hp = RecordHeap(r); /* visit all fields */ i > 0; /* */ i -= 2) /* */ { s = *hp++; /* */ t = *hp++; /* */ if (t != StringNULL) /* */ { provide_to_record(rec,s,t); } /* */ } /* */ } /* */ /* */ return FALSE; /* */ } /*------------------------*/ BibTool/database.c0000644000175100017510000017346512646457123012772 0ustar genegene/*** databse.c **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions which deal with databases. ** Databases are stored in an abstract datatype |DB| which is defined ** in |database.h|. Methods are provided to query and modify a database. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif DB new_db _ARG((void)); /* */ Record db_find _ARG((DB db, String key)); /* */ Record db_search _ARG((DB db, String key)); /* */ String db_new_key _ARG((DB db, String key)); /* */ String db_string _ARG((DB db, String s, int localp));/* */ int * db_count _ARG((DB db, int *lp)); /* */ int read_db _ARG((DB db, String file, int verbose));/* */ static Record insert_record _ARG((Record rec, Record ptr,int (*less)_ARG((Record, Record))));/**/ static Record rec__sort _ARG((Record rec,int (*less)_ARG((Record, Record))));/**/ static int cmp_heap _ARG((Record r1, Record r2)); /* */ static void mark_string _ARG((Record rec, String s));/* */ void db_insert _ARG((DB db,Record rec,int verbose));/* */ void db_forall _ARG((DB db,int (*fct)_ARG((DB, Record))));/* */ void db_mac_sort _ARG((DB db)); /* */ void db_rewind _ARG((DB db)); /* */ void db_sort _ARG((DB db,int (*less)_ARG((Record, Record))));/* */ void db_xref_undelete _ARG((DB db)); /* */ void delete_record _ARG((DB db, Record rec)); /* */ void free_db _ARG((DB db)); /* */ void print_db _ARG((FILE *file, DB db, char *spec));/* */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ #define SkipWarning WARNING("Skiping to next '@'") /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: new_db() ** Purpose: Create a new database and initialize it to contain no ** information. ** If no memory is left then an error is raised and the program ** is terminated. ** Arguments: none ** Returns: The new database. **___________________________________________________ */ DB new_db() /* */ { register DB new; /* */ /* */ if ((new=(DB)malloc(sizeof(sDB))) == NoDB) /* */ { OUT_OF_MEMORY("db"); } /* */ DBnormal(new) = RecordNULL; /* */ DBstring(new) = RecordNULL; /* */ DBpreamble(new) = RecordNULL; /* */ DBcomment(new) = RecordNULL; /* */ DBalias(new) = RecordNULL; /* */ DBinclude(new) = RecordNULL; /* */ DBmodify(new) = RecordNULL; /* */ return new; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_db() ** Purpose: Deallocate the memory occupied by a database. ** Note that any references to this database becomes invalid. ** Arguments: ** db Database to release. ** Returns: nothing **___________________________________________________ */ void free_db(db) /* */ DB db; /* */ { /* */ free_record(DBnormal(db)); /* */ free_record(DBstring(db)); /* */ free_record(DBpreamble(db)); /* */ free_record(DBcomment(db)); /* */ free_record(DBalias(db)); /* */ free_record(DBinclude(db)); /* */ free_record(DBmodify(db)); /* */ free(db); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: apply_modify() ** Type: int ** Purpose: ** ** Arguments: ** db the database ** key the key ** rec the record ** Returns: **___________________________________________________ */ int apply_modify(db, key, rec) /* */ DB db; /* */ String key; /* */ Record rec; /* */ { String *hp = RecordHeap(rec); /* */ int i; /* */ Record r = db_find(db,key); /* */ if (r == RecordNULL) /* */ { WARNING2("Entry to modify not found: ",key); /* */ return 0; /* */ } /* */ DebugPrint2("Modify ",*RecordHeap(rec)); /* */ /* */ for ( i = RecordFree(rec); i > 0; i -= 2 ) /* */ { /* No deleted or */ if ( *hp && is_allowed(**hp) && *(hp+1) ) /* private entry */ { DebugPrint3(*hp," => ",*(hp+1)); /* */ push_to_record(r, *hp, *(hp+1)); /* */ } /* */ hp += 2; /* Goto next pair. */ } /* */ return 1; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: apply_alias() ** Type: int ** Purpose: ** ** Arguments: ** db the database ** key the key ** rec the record ** verbose the verbose indicator ** Returns: **___________________________________________________ */ int apply_alias(db, key, rec, verbose) /* */ DB db; /* */ String key; /* */ Record rec; /* */ int verbose; /* */ { Record r = db_find(db, key); /* */ if (r == RecordNULL) /* */ { WARNING2("Entry to alias not found: ",key); /* */ return 0; /* */ } /* */ DebugPrint2("Alias ",*RecordHeap(rec)); /* */ /* */ r = copy_record(r); /* Make a private copy. */ RecordOldKey(r) = *RecordHeap(rec); /* */ *RecordHeap(r) = *RecordHeap(rec); /* */ db_insert(db, r, verbose); /* */ return 1; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_insert() ** Purpose: Add a record to a database. ** The record can be any kind of record. It is added to the ** appropriate category. ** Arguments: ** db Database to insert the record into. ** rec Record to add to the database. ** verbose Boolean to determine whether progress should be reported. ** Returns: nothing **___________________________________________________ */ void db_insert(db, rec, verbose) /* */ DB db; /* */ Record rec; /* */ int verbose; /* */ { Record *rp; /* */ /* */ switch ( RecordType(rec) ) /* */ { case BIB_STRING: /* */ rp = &DBstring(db); /* */ DebugPrint1("Inserting String"); /* */ break; /* */ case BIB_PREAMBLE: /* */ rp = &DBpreamble(db); /* */ DebugPrint1("Inserting Preamble"); /* */ break; /* */ case BIB_COMMENT: /* */ rp = &DBcomment(db); /* */ DebugPrint1("Inserting Comment"); /* */ break; /* */ case BIB_MODIFY: /* */ if(rsc_apply_modify && /* */ apply_modify(db, *RecordHeap(rec), rec)) /* */ { free_record(rec); /* */ return; /* */ } else { /* */ rp = &DBmodify(db); /* */ DebugPrint1("Inserting Modify"); /* */ } /* */ break; /* */ case BIB_INCLUDE: /* */ if(rsc_apply_include) /* */ { DebugPrint2("Including ",*RecordHeap(rec));/* */ if (read_db(db,*RecordHeap(rec),verbose)) /* */ { ERROR2("File not found: ",*RecordHeap(rec));/* */ } /* */ free_record(rec); /* */ return; /* */ } else { /* */ rp = &DBinclude(db); /* */ DebugPrint1("Inserting Include"); /* */ } /* */ break; /* */ case BIB_ALIAS: /* */ if (rsc_apply_alias) /* */ { DebugPrint2("Alias ",*RecordHeap(rec)); /* */ apply_alias(db, *(RecordHeap(rec)+1), /* */ rec, verbose); /* */ free_record(rec); /* */ return; /* */ } else { /* */ rp = &DBalias(db); /* */ DebugPrint1("Inserting Alias"); /* */ } /* */ break; /* */ default: /* */ rp = &DBnormal(db); /* */ DebugPrint2("Inserting Entry ", /* */ *RecordHeap(rec)); /* */ break; /* */ } /* */ /* */ if ( *rp == RecordNULL ) /* List is empty */ { *rp = rec; } /* Just remember the rec. */ else /* */ { NextRecord(*rp) = rec; /* */ PrevRecord(rec) = *rp; /* */ *rp = rec; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: read_db() ** Purpose: Read records from a file and add them to a database. ** A function has to be given as one argument. This function is ** called for each record. If this function returns |TRUE| then ** the record is added to the database. Otherwise the record is ** discarded. ** ** The progress of reading is reported to |stderr| if the ** boolean argument |verbose| is |TRUE|. ** Arguments: ** db Database to augment. ** file File name to read from. ** verbose Boolean to determine whether progress should be reported. ** Returns: 1 if the file can not be opened. 0 otherwise. **___________________________________________________ */ int read_db(db, file, verbose) /* */ DB db; /* */ String file; /* */ int verbose; /* */ { register int type; /* */ static Record master_record = RecordNULL; /* */ Record rec; /* */ register Record dbn; /* */ /* */ if ( !see_bib(file) ) { return 1; } /* */ if ( master_record == RecordNULL ) /* */ { master_record = new_record(0,32); } /* */ RecordSource(master_record) = (file==NULL /* */ ?sym_empty /* */ :symbol(file)); /* */ /* */ if ( file == NULL ) file = (String)""; /* */ if ( verbose ) /* If desired print an */ { VerbosePrint2("Reading ",file); } /* open message. */ /* */ dbn = DBnormal(db); /* */ if ( dbn != RecordNULL ) /* */ { /* */ while ( NextRecord(dbn) != RecordNULL ) /* */ { dbn = NextRecord(dbn); } /* */ } /* */ DBnormal(db) = dbn; /* */ /* */ for (type = parse_bib(master_record); /* */ type != BIB_EOF; /* */ type = parse_bib(master_record)) /* */ { /* */ if ( type < 0 ) /* Errors give rise to */ { SkipWarning; } /* a warning. */ else if ( IsSpecialRecord(type) ) /* STRING/PREAMBLE/COMMENT*/ { db_insert(db, /* */ copy_record(master_record), /* */ verbose); /* */ } /* */ else /* */ { rec = copy_record(master_record); /* Make a private copy. */ RecordOldKey(rec) = *RecordHeap(rec); /* */ db_insert(db,rec, verbose); /* */ if ( verbose ) { ErrC('+'); FlushErr; } /* */ } /* */ } /* */ /* */ if ( verbose ) /* If desired print a */ { VerbosePrint2("Done with ",file); } /* close message. */ /* */ (void)seen(); /* Close the file. */ /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: mark_string() ** Purpose: ** ** ** Arguments: ** rec the record ** s ** Returns: nothing **___________________________________________________ */ static void mark_string(rec, s) /* */ Record rec; /* */ String s; /* */ { int d; /* */ Record r; /* */ /* */ while (*s) /* */ { /* */ switch (*s) /* */ { case '\0': return; /* */ case '"': /* */ d = 0; /* */ while ( *++s && (*s != '"' || d > 0) ) /* */ { switch (*s) /* */ { case '{': d++; break; /* */ case '}': d--; break; /* */ case '\\': if (s[1]) s++; /* */ } /* */ } /* */ if ( *s ) s++; /* */ break; /* */ case '{': /* */ d = 1; /* */ while ( *++s && d > 0 ) /* */ { switch (*s) /* */ { case '{': d++; break; /* */ case '}': d--; break; /* */ case '\\': if (s[1]) s++; /* */ } /* */ } /* */ if ( *s ) s++; /* */ break; /* */ default: /* */ if ( is_allowed(*s) ) /* */ { Uchar c; /* */ String t; /* */ String mac = s; /* */ while ( is_allowed(*s) ) s++; /* */ c = *s; /* */ *s ='\0'; /* */ t = new_Ustring(mac); /* */ *s = c; /* */ mac = sym_add(t,0); /* */ free(t); /* */ for (r = rec; r; r = NextRecord(r)) /* */ { /* */ if ( *RecordHeap(r) == mac ) /* */ { /* */ SetRecordMARK(r); /* */ break; /* */ } /* */ } /* */ } /* */ else s++; /* */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: print_segment() ** Type: static void ** Purpose: ** ** Arguments: ** file ** db ** rec ** Returns: nothing **___________________________________________________ */ static void print_segment(file, db, rec, allp) /* */ FILE *file; /* */ DB db; /* */ Record rec; /* */ int allp; /* */ { /* */ if (rec == RecordNULL) return; /* */ /* */ while (PrevRecord(rec) != RecordNULL) /* Rewind to beginning. */ { rec = PrevRecord(rec); } /* */ /* */ while (rec != RecordNULL) /* */ { /* */ if (!RecordIsDELETED(rec)) /* */ { /* */ if ( allp || RecordIsMARKED(rec) ) /* */ { /* */ fput_record(file, rec, db, (String)"@"); /* */ } /* */ } /* */ else if ( rsc_del_q ) /* */ { fput_record(file, rec,db, rsc_del_pre); } /* */ rec = NextRecord(rec); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: preprint_string() ** Type: static void ** Purpose: ** ** Arguments: ** file ** db ** strings ** rec ** Returns: nothing **___________________________________________________ */ static void preprint_string(file, db, strings, rec)/* */ FILE *file; /* */ DB db; /* */ Record strings; /* */ Record rec; /* */ { int i; /* */ int d; /* */ Record r; /* */ /* */ for ( i=0; i < RecordFree(rec); i+=2 ) /* */ { if ( RecordHeap(rec)[i] != NULL ) /* */ { String s = RecordHeap(rec)[i+1]; /* */ /* */ while(*s) /* */ { /* */ switch (*s) /* */ { case '\0': return; /* */ case '"': /* */ d = 0; /* */ while ( *++s && (*s!='"' || d>0) ) /* */ { switch (*s) /* */ { case '{': d++; break; /* */ case '}': d--; break; /* */ case '\\': if (s[1]) s++; /* */ } /* */ } /* */ if ( *s ) s++; /* */ break; /* */ case '{': /* */ d = 1; /* */ while ( *++s && d>0 ) /* */ { switch (*s) /* */ { case '{': d++; break; /* */ case '}': d--; break; /* */ case '\\': if (s[1]) s++; /* */ } /* */ } /* */ if ( *s ) s++; /* */ break; /* */ default: /* */ if ( is_allowed(*s) ) /* */ { Uchar c; /* */ String t; /* */ String mac = s; /* */ while ( is_allowed(*s) ) s++; /* */ c = *s; /* */ *s ='\0'; /* */ t = new_Ustring(mac); /* */ *s = c; /* */ mac = sym_add(t,0); /* */ free(t); /* */ /* */ for (r = strings; /* */ r != RecordNULL; /* */ r = NextRecord(r) ) /* */ { /* */ if ( *RecordHeap(r) == mac && /* */ RecordIsMARKED(r) ) /* */ { /* */ ClearRecordMARK(r); /* */ fput_record(file,r,db,(String)"@");/* */ /* */ preprint_string(file, /* */ db, /* */ strings, /* */ r); /* */ } /* */ } /* */ } /* */ else s++; /* */ } /* */ } /* */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: print_strings() ** Type: static void ** Purpose: ** ** Arguments: ** file ** db ** allp ** Returns: nothing **___________________________________________________ */ static void print_strings(file, db, allp) /* */ FILE *file; /* */ DB db; /* */ int allp; /* */ { Record strings = DBstring(db); /* */ Record rec; /* */ /* */ if ( strings == RecordNULL ) return; /* */ /* */ while (PrevRecord(strings) ) /* find beginning */ { strings = PrevRecord(strings); } /* of strings */ /* */ if ( allp ) /* */ { /* */ for (rec = strings; /* */ rec != RecordNULL; /* */ rec = NextRecord(rec)) /* */ { SetRecordMARK(rec); } /* */ } /* */ else /* */ { int i; /* */ /* */ for (rec = strings; /* reset all marks */ rec != RecordNULL; /* */ rec = NextRecord(rec)) /* */ { ClearRecordMARK(rec); } /* */ /* */ if ( (rec=DBnormal(db)) != RecordNULL ) /* */ { /* */ while ( PrevRecord(rec) ) rec = PrevRecord(rec);/* */ /* */ for ( ; /* */ rec != RecordNULL; /* */ rec = NextRecord(rec)) /* */ { /* */ if ( !RecordIsDELETED(rec) ) /* */ { /* */ for (i = 2; i < RecordFree(rec); i += 2) /* */ { if ( RecordHeap(rec)[i] != NULL ) /* */ { mark_string(strings, /* */ RecordHeap(rec)[i+1]); /* */ } /* */ } /* */ } /* */ } /* */ /* */ for (rec = strings; /* mark the dependencies */ rec != RecordNULL; /* from within strings */ rec = NextRecord(rec)) /* */ { /* */ if (RecordIsMARKED(rec)) /* */ { /* */ for (i = 1; i < RecordFree(rec); i++) /* */ { if ( RecordHeap(rec)[i] != NULL ) /* */ { mark_string(strings,RecordHeap(rec)[i]);/* */ } /* */ } /* */ } /* */ } /* */ } /* */ } /* */ /* */ for (rec = strings; /* */ rec != RecordNULL; /* */ rec = NextRecord(rec)) /* */ { /* */ if (!RecordIsDELETED(rec) && /* */ RecordIsMARKED(rec) ) /* */ { preprint_string(file,db,strings,rec); } /* */ } /* */ /* */ print_segment(file, db, strings, FALSE); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: print_db() ** Purpose: Print a database to a file in a way which is readable by ** \BibTeX. The spec determines which parts should be ** printed and the order of this parts. The spec is ** processed from left to right. Each unknown character ** is silently ignored. The following characters ** correspond to parts of the database: ** \begin{description} ** \item [p] The preamble. ** \item [\$] All strings (macros) contained in the database. ** \item [S] The strings (macros) which are used in the ** database. ** \item [s] The strings (macros) contained in the database ** where the resource print.all.strings determines ** whether all strings should be printed or the used ** strings only. ** \item [n] The normal records. ** \item [c] The comments. ** \item [i] The includes. ** \item [a] The aliases. ** \item [m] The modifies. ** \end{description} ** Upper-case letters which are not mentioned are silently folded ** to their lower-case counterparts. ** Arguments: ** file The file handle for printing. ** db The database to print ** spec String containing the specification of the parts to print. ** Returns: nothing **___________________________________________________ */ void print_db(file,db,spec) /* */ FILE *file; /* */ DB db; /* */ char *spec; /* */ { /* */ while ( *spec ) /* */ { switch ( *(spec++) ) /* */ { case 'p': case 'P': /* */ print_segment(file, db, DBpreamble(db), TRUE);/* */ break; /* */ case 'n': case 'N': /* */ print_segment(file, db, DBnormal(db), TRUE);/* */ break; /* */ case 's': /* */ print_strings(file, db, rsc_all_macs); /* */ break; /* */ case '$': /* */ print_strings(file, db, TRUE); /* */ break; /* */ case 'S': /* */ print_strings(file, db, FALSE); /* */ break; /* */ case 'c': case 'C': /* */ print_segment(file, db, DBcomment(db), TRUE);/* */ break; /* */ case 'i': case 'I': /* */ print_segment(file, db, DBinclude(db), TRUE);/* */ break; /* */ case 'a': case 'A': /* */ print_segment(file, db, DBalias(db), TRUE);/* */ break; /* */ case 'm': case 'M': /* */ print_segment(file, db, DBmodify(db), TRUE);/* */ break; /* */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: delete_record() ** Purpose: Delete a record from a database. ** It is not checked, that the record really is part of the ** database. The record is just unlinked from its ** list. Just in case the record should be the first one ** the database record is modified. ** Arguments: ** db Database containing |rec|. ** rec Record to delete. ** Returns: nothing **___________________________________________________ */ void delete_record(db,rec) /* */ DB db; /* */ Record rec; /* */ { Record *rp; /* */ /* */ switch (RecordType(rec)) /* */ { case BIB_PREAMBLE: rp = &DBpreamble(db); break;/* */ case BIB_STRING: rp = &DBstring(db); break;/* */ case BIB_COMMENT: rp = &DBcomment(db); break;/* */ case BIB_MODIFY: rp = &DBmodify(db); break;/* */ case BIB_INCLUDE: rp = &DBinclude(db); break;/* */ case BIB_ALIAS: rp = &DBalias(db); break;/* */ default: rp = &DBnormal(db); break;/* */ } /* */ if ( rec == *rp ) /* */ { if ( NextRecord(rec) != RecordNULL ) /* */ { *rp = NextRecord(rec); } /* */ else if ( PrevRecord(rec) != RecordNULL ) /* */ { *rp = PrevRecord(rec); } /* */ else /* */ { *rp = RecordNULL; } /* */ } /* */ if ( PrevRecord(rec) != RecordNULL ) /* */ { NextRecord(PrevRecord(rec)) = NextRecord(rec); }/* */ if ( NextRecord(rec) != RecordNULL ) /* */ { PrevRecord(NextRecord(rec)) = PrevRecord(rec); }/* */ free_1_record(rec); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_forall() ** Purpose: Visit all normal records in the data base and apply the given ** function |fct| to each. ** If this function returns |TRUE| then no more records need to ** be visited. ** No special order can be assumed in which the records are seen. ** Arguments: ** fct Boolean valued function determining the end of the ** processing. It takes two arguments a |DB| and a |Record|. ** Returns: nothing **___________________________________________________ */ void db_forall(db,fct) /* */ DB db; /* */ int (*fct)_ARG((DB,Record)); /* Function pointer */ { register Record rec, next; /* */ /* */ if ( DBnormal(db) == RecordNULL ) return; /* */ /* */ for (rec = DBnormal(db); /* */ rec != RecordNULL; /* */ rec = next) /* */ { next = NextRecord(rec); /* */ if ( !RecordIsDELETED(rec) && /* */ (*fct)(db,rec) ) return; /* */ } /* */ /* */ for (rec = PrevRecord(DBnormal(db)); /* */ rec != RecordNULL; /* */ rec = next) /* */ { next = PrevRecord(rec); /* */ if ( !RecordIsDELETED(rec) && /* */ (*fct)(db,rec) ) return; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_find() ** Purpose: Search the database for a record with a given key. ** If |RecordOldKey| is set for the record then use this value. ** Otherwise use |*Heap|. |*Heap| contains the reference ** key of normal records. ** ** Deleted records are ignored. An arbitrary matching ** record is returned. Thus if more than one record have ** the same key then the behavior is nondeterministic. ** Arguments: ** db Database to search in. ** key the key to search for ** Returns: nothing **___________________________________________________ */ Record db_find(db,key) /* */ DB db; /* */ String key; /* */ { register Record rec; /* */ /* */ DebugPrint2("Finding... ",key); /* */ /* */ if ( DBnormal(db) == RecordNULL ) return RecordNULL;/* */ /* */ for (rec = DBnormal(db); /* */ rec != RecordNULL; /* */ rec = NextRecord(rec)) /* */ { /* */ if ( !RecordIsDELETED(rec) ) /* */ { if ( RecordOldKey(rec) != NULL ) /* */ { if ( RecordOldKey(rec) == key ) return rec; }/* */ else if ( *RecordHeap(rec) == key ) return rec;/* */ } /* */ } /* */ /* */ for (rec = PrevRecord(DBnormal(db)); /* */ rec != RecordNULL; /* */ rec = PrevRecord(rec)) /* */ { /* */ if ( !RecordIsDELETED(rec) ) /* */ { if ( RecordOldKey(rec) != NULL ) /* */ { if ( RecordOldKey(rec) == key ) return rec; }/* */ else if ( *RecordHeap(rec) == key ) return rec; /* */ } /* */ } /* */ return RecordNULL; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_search() ** Purpose: Search the database for a record with a given key. ** If |RecordOldKey| is set for the record then use this value. ** Otherwise use |*Heap|. |*Heap| contains the reference ** key of normal records. ** ** Deleted records are not ignored! An arbitrary matching ** record is returned. Thus if more than one record have ** the same key then the behavior is nondeterministic. ** Arguments: ** db Database to search in. ** key the key to search for ** Returns: nothing **___________________________________________________ */ Record db_search(db, key) /* */ DB db; /* */ String key; /* */ { register Record rec; /* */ /* */ if ( DBnormal(db) == RecordNULL ) return RecordNULL;/* */ /* */ for (rec = DBnormal(db); /* */ rec != RecordNULL; /* */ rec = NextRecord(rec)) /* */ { if ( RecordOldKey(rec) != NULL ) /* */ { if ( RecordOldKey(rec) == key ) return rec; }/* */ else if ( *RecordHeap(rec) == key ) return rec; /* */ } /* */ /* */ for (rec = PrevRecord(DBnormal(db)); /* */ rec != RecordNULL; /* */ rec = PrevRecord(rec)) /* */ { if ( RecordOldKey(rec) != NULL ) /* */ { if ( RecordOldKey(rec) == key ) return rec; }/* */ else if ( *RecordHeap(rec) == key ) return rec;/* */ } /* */ return RecordNULL; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_new_key() ** Purpose: Search the database for a record with a given old key and ** return the new one. ** Arguments: ** db Database to search in. ** key Key to find. ** Returns: nothing **___________________________________________________ */ String db_new_key(db,key) /* */ DB db; /* */ String key; /* */ { register Record rec; /* */ /* */ if ( DBnormal(db) == RecordNULL ) return NULL; /* */ /* */ for (rec = DBnormal(db); /* */ rec != RecordNULL; /* */ rec = NextRecord(rec)) /* */ { /* */ if (RecordOldKey(rec) != NULL && /* */ RecordOldKey(rec) == key) /* */ return *RecordHeap(rec); /* */ } /* */ /* */ for (rec = PrevRecord(DBnormal(db)); /* */ rec != RecordNULL; /* */ rec = PrevRecord(rec)) /* */ { /* */ if (RecordOldKey(rec) != NULL && /* */ RecordOldKey(rec) == key) /* */ return *RecordHeap(rec); /* */ } /* */ return NULL; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_rewind() ** Purpose: Rewind the normal records of a database to point to the first ** record if at least one records exists. Otherwise nothing is ** done. ** Arguments: ** db Database to rewind. ** Returns: nothing **___________________________________________________ */ void db_rewind(db) /* */ DB db; /* */ { /* */ if (DBnormal(db) == RecordNULL) return; /* */ /* */ while (PrevRecord(DBnormal(db)) != RecordNULL) /* */ { DBnormal(db) = PrevRecord(DBnormal(db)); } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rec__sort() ** Purpose: ** ** ** Arguments: ** rec ** less ** Returns: **___________________________________________________ */ static Record rec__sort(rec,less) /* */ Record rec; /* */ int (*less)_ARG((Record,Record)); /* Function pointer */ { Record r; /* */ Record new; /* */ /* */ if (rec == RecordNULL) return rec; /* */ r = RecordNULL ; /* */ /* */ while (PrevRecord(rec) != RecordNULL) /* */ { rec = PrevRecord(rec); } /* */ /* */ while (rec != RecordNULL) /* */ { new = rec; /* */ rec = NextRecord(rec); /* */ r = insert_record(new,r,less); /* */ } /* */ return r; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** The sorting uses a variant of insertion sort. ** Thus the major task is performed in this function, which is called to store ** a record. ** The Record structure contains two pointers to the same type. With those ** pointers a double linked list is established. sort_rec is either NULL --- ** if no record is stored --- or it is a pointer to some element in the ** ORDERED list: ** ** +------+ +------+ +------+ +------+ +------+ +------+ ** -->|Record|-->|Record|-->|Record|-->|Record|-->|Record|-->|Record|--> ** <--| |<--| |<--| |<--| |<--| |<--| |<-- ** +------+ +------+ +------+ +------+ +------+ +------+ ** ^ ** db_______| ** ** With this picture in mind it's obvious what's to be done. ** There are two major cases. To find the right position to insert the new ** record ** - either the pointer has to be moved leftward ** - or the pointer has to be moved rightward ** ** Special cases have to be considered if the new record is to be inserted ** before the first or after the last element in the list. ** ** The rest is simply leg work. ** ** Well, a word on the complexity. ** If the input is almost sorted (correct or in reverse order) then the ** algorithm is linear. ** In the worst case the algorithm is quadratic. This worst case looks as ** follows: ** A record has to be inserted which is smaller than the least element in the ** list. Afterwards one which is greater than the largest. ** ** NOTE: CURRENTLY THE ALGORITHM IS NOT STABLE: ** Records with the same key may get mixed in the sorted list. **___________________________________________________ */ static Record insert_record(rec,ptr,less) /* */ register Record rec; /* */ register Record ptr; /* */ int (*less)_ARG((Record,Record)); /* Function pointer */ { /* */ if (ptr == RecordNULL) { /* List is empty */ PrevRecord(rec) = RecordNULL; /* */ NextRecord(rec) = RecordNULL; /* */ return rec; /* */ } /* */ /* */ if ( (*less)(rec,ptr) ) /* */ { /* */ while (PrevRecord(ptr) != RecordNULL) /* Move leftward. */ { ptr = PrevRecord(ptr); /* */ if ( !(*less)(rec,ptr) ) /* */ { PrevRecord(rec) = ptr; /* Insert */ NextRecord(rec) = NextRecord(ptr);/* */ PrevRecord(NextRecord(rec))= rec; /* */ NextRecord(ptr) = rec; /* */ return rec; /* */ } /* */ } /* */ PrevRecord(ptr) = rec; /* Insert before the first*/ NextRecord(rec) = ptr; /* */ PrevRecord(rec) = RecordNULL; /* */ } /* */ else /* */ { /* */ while (NextRecord(ptr) != RecordNULL) /* Move rightward. */ { ptr = NextRecord(ptr); /* */ if ( (*less)(rec,ptr) ) /* */ { NextRecord(rec) = ptr; /* Insert */ PrevRecord(rec) = PrevRecord(ptr);/* */ NextRecord(PrevRecord(rec))= rec; /* */ PrevRecord(ptr) = rec; /* */ return rec; /* */ } /* */ } /* */ NextRecord(ptr) = rec; /* Insert after the last. */ PrevRecord(rec) = ptr; /* */ NextRecord(rec) = RecordNULL; /* */ } /* */ return rec; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: cmp_heap() ** Purpose: Compare the keys of two records. The keys are stored at the ** top of the heap. ** Arguments: ** r1 First record to compare. ** r2 Second record to compare. ** Returns: |TRUE| iff the first record is smaller than the second one. **___________________________________________________ */ static int cmp_heap(r1,r2) /* */ register Record r1; /* */ register Record r2; /* */ { return strcmp((char*)*RecordHeap(r1), /* */ (char*)*RecordHeap(r2))<0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_mac_sort() ** Purpose: Sort the macros of a database. The sorting uses ** increasing lexicographic order according to the ** character codes of the macro names. Note that this ** might lead to different results on machines with ** different character encodings, e.g.\ ASCII vs.\ EBCDIC. ** Arguments: ** db Database to sort. ** less comparison function to use. ** Returns: nothing **___________________________________________________ */ void db_mac_sort(db) /* */ DB db; /* */ { /* */ DBstring(db) = rec__sort(DBstring(db), cmp_heap);/* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_sort() ** Purpose: Sort the normal records of a database. As a side effect the ** records are kept in sorted order in the database. ** The sorting order can be determined by the argument |less| ** which is called to compare two records. ** Arguments: ** db Database to sort. ** less Comparison function to use. This boolean function ** takes two records and returns |TRUE| iff the first one ** is less than the second one. ** Returns: nothing **___________________________________________________ */ void db_sort(db,less) /* */ DB db; /* */ int (*less)_ARG((Record,Record)); /* Function pointer */ { /* */ DBnormal(db) = rec__sort(DBnormal(db), less); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_string() ** Purpose: Try to find the definition of a macro. ** First, the local values in the database |db| are considered. ** If this fails and |localp| is |FALSE| then the global list ** is searched aswell. If all fails |NULL| is returned. ** Arguments: ** db Database ** s Name of the \BibTeX{} macro to expand. ** localp Boolean determining whether the search is only local to the db. ** Returns: The macro expansion or |NULL| upon failure. **___________________________________________________ */ String db_string(db, s, localp) /* */ DB db; /* */ String s; /* */ int localp; /* */ { Record rec; /* */ /* */ if ((rec=DBstring(db))) /* */ { /* */ for ( ; rec; rec=NextRecord(rec) ) /* */ { if ( RecordHeap(rec)[0] == s ) /* */ { return RecordHeap(rec)[1]; } /* */ } /* */ for (rec = PrevRecord(DBstring(db)); /* */ rec; /* */ rec = PrevRecord(rec) ) /* */ { if ( RecordHeap(rec)[0] == s ) /* */ { return RecordHeap(rec)[1]; } /* */ } /* */ } /* */ /* */ return (localp?NULL:look_macro(s,0)); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_count() ** Purpose: Count all entries in a database. This includes normal ** as well as special records. The result is stored in a ** static array which is reused by |db_count()|. A ** pointer to this array is returned. The indices ** correspond to the entry types defined with ** |add_entry_type()| or declared as symbolic constants ** in |entry.h|. ** ** The end of the array is marked by an element ** containing a negative number. In addition the argument ** |lp| can point to an integer where the number of valid ** elements is stored. If |lp| is |NULL| this step is ** omitted. ** Arguments: ** db Database to count. ** lp pointer to an integer for the length. ** Returns: Static array containing the statistics. **___________________________________________________ */ int * db_count(db,lp) /* */ DB db; /* */ int *lp; /* */ { static int *count; /* */ static int len = 0; /* */ int i; /* */ Record rec; /* */ /* */ for (i = 5; get_entry_type(i) != NULL; i++) ; /* */ if ( lp ) *lp = i; /* */ i++; /* */ /* */ if (len == 0) /* */ { len = i; /* */ count = (int*)malloc(len*sizeof(int)); /* */ } /* */ else if (len != i) /* */ { len = i; /* */ count = (int*)realloc(count,len*sizeof(int)); /* */ } /* */ if (count == NULL) /* */ { OUT_OF_MEMORY("count"); } /* */ /* */ for (i = 0; i < len; i++) count[i] = 0; /* */ count[len-1] = -1; /* */ /* */ if ((rec=DBstring(db)) != RecordNULL) /* */ { while (PrevRecord(rec) != RecordNULL) rec = PrevRecord(rec);/* */ while (rec != RecordNULL) /* */ { count[BIB_STRING]++; /* */ rec = NextRecord(rec); /* */ } /* */ } /* */ if ((rec=DBcomment(db)) != RecordNULL) /* */ { while (PrevRecord(rec) != RecordNULL) rec = PrevRecord(rec);/* */ while (rec != RecordNULL) /* */ { count[BIB_COMMENT]++; /* */ rec = NextRecord(rec); /* */ } /* */ } /* */ if ( (rec=DBpreamble(db)) != RecordNULL) /* */ { while (PrevRecord(rec) != RecordNULL) rec = PrevRecord(rec);/* */ while (rec != RecordNULL) /* */ { count[BIB_PREAMBLE]++; /* */ rec = NextRecord(rec); /* */ } /* */ } /* */ if ((rec=DBalias(db)) != RecordNULL) /* */ { while (PrevRecord(rec) != RecordNULL) rec = PrevRecord(rec);/* */ while (rec != RecordNULL) /* */ { count[BIB_ALIAS]++; /* */ rec = NextRecord(rec); /* */ } /* */ } /* */ if ((rec=DBmodify(db)) != RecordNULL) /* */ { while (PrevRecord(rec) != RecordNULL) rec = PrevRecord(rec);/* */ while (rec != RecordNULL) /* */ { count[BIB_MODIFY]++; /* */ rec = NextRecord(rec); /* */ } /* */ } /* */ if ((rec=DBinclude(db)) != RecordNULL) /* */ { while (PrevRecord(rec) != RecordNULL) rec = PrevRecord(rec);/* */ while (rec != RecordNULL) /* */ { count[BIB_INCLUDE]++; /* */ rec = NextRecord(rec); /* */ } /* */ } /* */ if ((rec=DBnormal(db)) != RecordNULL) /* */ { while (PrevRecord(rec) != RecordNULL ) rec = PrevRecord(rec);/* */ while (rec != RecordNULL) /* */ { if ( !RecordIsDELETED(rec) ) count[RecordType(rec)]++;/* */ rec = NextRecord(rec); /* */ } /* */ } /* */ /* */ return count; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: db_xref_undelete() ** Type: void ** Purpose: Scan through the database and undelete all entries ** which are in the transitive closure wrt the crossref ** relation. Initially all not deleted entries are in the ** set to consider. ** Arguments: ** db Database to treat ** Returns: nothing **___________________________________________________ */ void db_xref_undelete(db) /* */ DB db; /* */ { Record rec = DBnormal(db); /* */ if ( rec == RecordNULL ) return; /* No entries left anyhow.*/ /* */ while ( PrevRecord(rec) != RecordNULL ) /* Rewind */ { rec = PrevRecord(rec); } /* */ /* */ for ( ; /* Phase: */ rec != RecordNULL; /* For all marked entries*/ rec = NextRecord(rec) ) /* which have a xref and */ { /* mark all xrefs. */ if ( RecordIsXREF(rec) && /* */ !RecordIsDELETED(rec) /* */ ) /* */ { String key = (String)"???"; /* */ int count; /* */ Record r = rec; /* */ /* */ for ( count=rsc_xref_limit; /* Prevent infinite loop */ count >= 0 && RecordIsXREF(r); /* */ count-- ) /* */ { /* */ if ((key = get_field(db, /* */ r, /* */ sym_crossref)) == NULL)/* */ { count = -1; /* */ } /* */ else /* */ { /* */ key = symbol(lower(expand_rhs(key, /* */ sym_empty, /* */ sym_empty, /* */ db))); /* */ if ( (r=db_search(db,key)) == RecordNULL )/* */ { ErrPrintF("*** BibTool: Crossref `%s' not found.\n",key);/* */ count = -1; /* */ } /* */ else if ( !RecordIsDELETED(r) ) /* */ { count = -1; } /* */ else /* */ { ClearRecordDELETED(r); /* */ } /* */ } /* */ } /* */ if (count == -1) /* */ { ErrPrintF("*** BibTool: Crossref limit exceeded; `%s' possibly looped.\n", key); /* */ } /* */ } /* */ } /* */ } /*------------------------*/ BibTool/entry.c0000644000175100017510000002116212646457135012354 0ustar genegene/*** entry.c ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions which deal with entry types. ** Right from the beginning only the special record types are ** known. Those special record types are |@Comment|, |@Preamble|, ** |@String|, |@Include|, |@Modify|, and |@Alias|. ** ** In addition to those special records the user can define ** additional record types which are denoted as ``normal''. E.g.\ ** usually |@Article| and |@Book| are defined which are ** ``normal'' record types. ** ** The record types are are managed in this module. In the other ** modules only numerical representations are used. This module ** provides means to map those numerical ids to the string ** representation and back. It is also possible to define ** additional record types. ** ** Part of this module is likely to be integrated into databases. ******************************************************************************/ #include #include #include #include #include "config.h" /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif static int match _ARG((String s, String t)); /* entry.c */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*****************************************************************************/ /*** ***/ /*****************************************************************************/ #define EntrySizeIncrement 8 String *entry_type; static int entry_ptr = 0; static int entry_size = 0; /*----------------------------------------------------------------------------- ** Function: init_entries() ** Purpose: Predefine some entry types which are stored at startup time ** in an array. The following entry types are predefined ** because they are considered special by \BibTeX: ** \begin{description} ** \item [BIB\_STRING] denotes a \BibTeX{} macro definition. ** \item [BIB\_PREAMBLE] denotes a preamble item which goes ** before the bibliography environment. ** \item [BIB\_COMMENT] denotes a comment entry which is ** passed to the output file. ** \item [BIB\_ALIAS] denotes an alias entry which renames an ** existing entry. ** \item [BIB\_MODIFY] denotes a modification request which ** alters an existing entry. ** \item [BIB\_INCLUDE] denotes an include request which reads ** in another \BibTeX{} file. ** \end{description} ** Note that this function is for internal purposes ** only. The normal user should call |init_bibtool()| ** instead. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void init_entries() /* */ { /* */ #ifdef INITIALIZE_BIBTEX_ENTRIES static char *word_list[] = /* default entry types. */ { INITIALIZE_BIBTEX_ENTRIES, NULL }; /* Mark the end with NULL */ register char**wp; /* */ #endif /* */ def_entry_type((String)"STRING" ); /* */ def_entry_type((String)"PREAMBLE"); /* */ def_entry_type((String)"COMMENT" ); /* */ def_entry_type((String)"ALIAS" ); /* */ def_entry_type((String)"MODIFY" ); /* */ def_entry_type((String)"INCLUDE" ); /* */ #ifdef INITIALIZE_BIBTEX_ENTRIES for ( wp = word_list; *wp != NULL; ++wp ) /* add compiled in types. */ { def_entry_type((String)(*wp)); } /* */ #endif } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: def_entry_type() ** Purpose: Dynamically define an entry type. If the entry type ** already exists then a new printing representation is ** stored. ** ** If no memory is left then an error is raised and the ** program is terminated ** Arguments: ** s String containing the name of the entry. ** Returns: nothing **___________________________________________________ */ void def_entry_type(s) /* */ String s; /* */ { int i; /* */ /* */ for (i = 0; i < entry_ptr; ++i) /* */ { /* */ if ( case_cmp(s,EntryName(i)) ) /* */ { free(EntryName(i)); /* */ EntryName(i) = new_Ustring(s); /* */ return; /* */ } /* */ } /* */ /* */ if ( entry_ptr <= entry_size ) /* */ { entry_size += EntrySizeIncrement; /* */ entry_type = ( entry_ptr == 0 /* */ ? (String*)malloc((size_t)(entry_size*sizeof(String))) : (String*)realloc((char*)entry_type, (size_t)(entry_size*sizeof(String))) ); /* */ if ( entry_type == (String*)NULL ) /* */ { OUT_OF_MEMORY("entry type"); } /* */ } /* */ entry_type[entry_ptr++] = new_Ustring(s); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: match() ** Purpose: Compare two strings ignoring case. ** Return TRUE iff they are identical or the second string is a ** substring not followed by a letter or digit. ** Arguments: ** s First string ** t Second string ** Returns: **___________________________________________________ */ static int match(s,t) /* */ register String s; /* */ register String t; /* */ { /* */ while( *t ) /* */ { if ( ToLower(*s) != ToLower(*t) ) return(FALSE);/* */ s++; t++; /* */ } /* */ return( is_alpha(*s) || is_digit(*s) ? FALSE : TRUE );/* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: find_entry_type() ** Purpose: Look up an entry type in the array of defined entries. ** Arguments: ** s String of the potential entry name. ** Returns: The index in the array or |NOOP|. **___________________________________________________ */ int find_entry_type(s) /* */ String s; /* */ { int i; /* */ /* */ for (i = 0; i < entry_ptr; ++i) /* */ { if ( match(s,EntryName(i)) ) /* */ { return(i); } /* */ } /* */ return BIB_NOOP; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: get_entry_type() ** Purpose: Get the printable string representation corresponding ** to the numerical entry type given as argument. If no ** entry type is defined for the given index then |NULL| ** is returned. ** Arguments: ** idx Index of entry type. ** Returns: Print representation of the entry type or |NULL|. **___________________________________________________ */ String get_entry_type(idx) /* */ int idx; /* */ { /* */ return (idx < 0 || idx >= entry_ptr /* */ ? NULL /* */ : EntryName(idx)); /* */ } /*------------------------*/ BibTool/error.c0000644000175100017510000001575612646457143012357 0ustar genegene/*** error.c ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** To ensure a consistent appearence of error messages \BibTool{} ** provides one generic error reporting routine. This routine is ** controlled by several arguments to allow maximum flexibility. ** ** Usually it is awkward to fill out all those arguments. To ** avoid this trouble the header file |error.h| provides some ** macros which cover the most common situation and hide ** unneccesary details. ** ******************************************************************************/ #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ extern int rsc_quiet; /*---------------------------------------------------------------------------*/ char *err_format = "*** BibTool: %s"; String err_point = (String)"."; String err_oom = (String)"Out of memory for "; FILE * err_file = NULL; /*----------------------------------------------------------------------------- ** Function: init_error() ** Type: void ** Purpose: ** Initialize the error reporting. ** Arguments: ** file the output file to write error messages to ** ** Returns: nothing **___________________________________________________ */ void init_error(file) /* */ FILE * file; /* */ { /* */ err_file = file; /* */ } /*------------------------*/ #define ErrNL (void)fputc('\n',err_file) #define ErrChar(C) (void)fputc(C,err_file) #define ErrS(S) (void)fputs(S,err_file) /*----------------------------------------------------------------------------- ** Function: error() ** Purpose: This is the generic error printing routine. ** It prints an error message together with an optional filename, ** the line number, the errorous line and a pointer to the ** problematic position. ** ** All parts of an error message are optional and can be ** suppressed under certain conditions. The error type ** determines which parts are actually shown. It is a ** boolean combination of the following flags which are ** defined in |error.h|: ** \begin{description} ** \item[ERR\_ERROR] If this bit is set then the error ** message is marked as ``error''. The flag |ERR_WARNING| ** is ignored in this case. This kind of messages can not ** be suppresed. ** \item[ERR\_WARNING] If this bit is set and ** |ERR_ERROR| is not set then the error message is ** marked as ``warning''. |ERR_WARNING| is ignored ** in this case. ** \item[ERR\_POINT] If this bit is set then the line |line| is ** shown together with a pointer to the byte pointed to ** by |err_pos|. Otherwise the line is not shown. ** \item[ERR\_FILE] If this bit is set then the name of ** the file |file_name| and the line number |lineno| are ** shown. Otherwise the file name and the line number are ** suppressed. ** \item[ERR\_EXIT] If this bit is set then the error ** routine calls |exit(-1)| at the end. This implicitly ** sets the |ERR_ERROR| bit as well. ** \end{description} ** ** The error message itself can be split in up to three ** strings |s1|, |s2|, and |s3|. Those strings are ** concatenated. They can also be |NULL| in which case ** they are ignored. ** ** The error message is written to the stream determined ** by the variable |err_file|. This variable refers to ** the |stderr| stream initially but can be redirected to ** any other destination. ** ** Arguments: ** type Error type: boolean combination of the error bits as ** defined in |error.h|. ** s1 1$^\mathrm{st}$ error message or |NULL|. ** s2 2$^\mathrm{nd}$ error message or |NULL|. ** s3 3$^\mathrm{rd}$ error message or |NULL|. ** line Current line when error occured (for reading errors). ** err_pos Error position in line |line|. ** line_no The line number where the error occurred. ** fname The file name where the error occurred. ** Returns: nothing **___________________________________________________ */ void error(type, s1, s2, s3, line, err_pos, line_no, fname)/* */ int type; /* defined in error.h */ String s1; /* 1st error message */ String s2; /* 2nd error message */ String s3; /* 3rd error message */ String line; /* line_no string. */ String err_pos; /* error position in line */ int line_no; /* line number */ char *fname; /* file name */ { /* */ if ( (type&ERR_ERROR) == 0 && rsc_quiet ) return;/* anything less than an */ /* error is ignored. */ ErrNL; /* */ if ( (type&ERR_POINT) && line != NULL ) /* */ { ErrS((char*)line); /* print the error line. */ if ( line[strlen((char*)line)-1] != '\n' ) ErrNL;/* */ for ( ; line #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String expand_rhs _ARG((String s,String pre,String post,DB db));/* expand.c*/ static int expand _ARG((String s,StringBuffer *sb,int brace,int first,String q_open,String q_close,DB db));/* expand.c*/ static void expand__ _ARG((String s,StringBuffer *sb,String q_open,String q_close,DB db));/* expand.c*/ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: expand_rhs() ** Purpose: Expand the right hand side of an item. Each macro ** which is defined in this database is replaced by its ** value. The result is kept in a static variable until ** the next invocation of this function overwrites it. ** Arguments: ** s String to expand ** pre This is the opening brace character to be used. For ** \BibTeX{} the valid values are |{| or |"|. This value ** has to match to |post|. ** post This is the closing brace character to be used. For ** \BibTeX{} the valid values are |}| or |"|. This value ** has to match to |pre|. ** db Database containing the macros. ** Returns: A pointer to the expanded string. This value is kept in a ** static variable of this function and will be overwritten with ** the next invocation. **___________________________________________________ */ String expand_rhs(s,pre,post,db) /* */ String s; /* */ String pre; /* */ String post; /* */ DB db; /* */ { static StringBuffer *sb = NULL; /* */ /* */ DebugPrint1("expand_rhs"); /* */ if ( sb == NULL && (sb = sbopen()) == NULL ) /* */ { OUT_OF_MEMORY("string expansion");} /* */ /* */ DebugPrint2("Expanding ",s); /* */ /* */ sbrewind(sb); /* */ expand__(s, sb, pre, post, db); /* */ return (String)sbflush(sb); /* */ } /*------------------------*/ #define PUTS(S,SB) (void)sbputs((char*)S,SB) #define PUTC(C,SB) (void)sbputchar(C,SB) /*----------------------------------------------------------------------------- ** Function: expand__() ** Purpose: Wrapper for expand(). ** Things have to be cleaned up afterwards. ** Arguments: ** s ** sb ** q_open ** q_close ** db ** Returns: nothing **___________________________________________________ */ static void expand__(s, sb, q_open, q_close, db) /* */ register String s; /* */ StringBuffer *sb; /* */ String q_open; /* */ String q_close; /* */ DB db; /* */ { /* */ if ( ! expand(s,sb,TRUE,TRUE,q_open,q_close,db) )/* */ { PUTS(q_close, sb); } /* */ else if ( sbtell(sb) == 0 ) /* */ { PUTS(q_open, sb); /* */ PUTS(q_close, sb); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: expand() ** Purpose: ** ** ** Arguments: ** s String to apply expansion to. ** sb String buffer which will receive the output. ** brace Boolean. Determine if braces should be used. ** The strings of the braces are in q_open and q_close. ** first In multi parts determine if this is the first part. ** q_open Open delimiter. This is an open brace or a double quote. ** q_close Close delimiter. This is a close brace or a double quote. ** Returns: **___________________________________________________ */ static int expand(s, sb, brace, first, q_open, q_close, db)/* */ register String s; /* specification */ StringBuffer *sb; /* output device */ int brace; /* is a brace needed? */ int first; /* is this the first part?*/ String q_open; /* open delimiter */ String q_close; /* close delimiter */ DB db; /* */ { /* */ while ( *s ) /* */ { /* */ switch ( *s ) /* */ { case '\0': break; /* Just in case. */ case '"': /* Start a string part. */ DebugPrint2("Start String:", s); /* */ if ( *++s == '"' ) { ++s; break; } /* Ignore the empty string*/ if ( brace ) /* */ { if ( !first ) { PUTS(" # ",sb); } /* */ PUTS(q_open,sb); brace = FALSE; /* */ } /* */ first = FALSE; /* */ /* */ for ( ; *s && *s != '"'; ++s ) /* Until the end is found */ { PUTC(*s,sb); /* transfer character. */ if ( *s == '\\' && *(s+1) ) /* \ is for quoting. */ { ++s; PUTC(*s,sb); } /* */ } /* */ if ( *s ) ++s; /* Advance if not end */ break; /* */ case '{': /* Start a block. */ DebugPrint2("Start block:",s); /* */ if ( *++s == '}' ) { ++s; break; } /* Ignore empty block. */ if ( brace ) /* */ { if ( !first ) { PUTS(" # ",sb); } /* */ PUTS(q_open,sb); brace = FALSE; /* */ } /* */ first = FALSE; /* */ /* */ { register int level = 1; /* Initialize brace count */ for ( ; *s && level > 0; ++s ) /* Until level 0 or end */ { switch ( *s ) /* */ { case '\\': /* \ is for quoting. */ PUTC(*s,sb); /* */ if ( *++s ) { PUTC(*s,sb); } /* */ break; /* */ case '{': /* */ ++level; /* */ PUTC(*s,sb); /* */ break; /* */ case '}': /* */ if ( --level > 0 ) PUTC(*s,sb); /* */ break; /* */ default: /* */ PUTC(*s,sb); /* */ } /* */ } /* */ } /* */ break; /* */ case '#': ++s; break; /* Silently assume #. */ case '0': case '1': case '2': case '3': case '4':/* Start a number */ case '5': case '6': case '7': case '8': case '9':/* */ DebugPrint2("Start number:",s); /* */ /* */ if ( brace ) /* */ { if ( !first ) { PUTS(" # ",sb); } /* */ PUTS(q_open,sb); brace = FALSE; /* */ } /* */ first = FALSE; /* */ /* */ do /* */ { PUTC(*s,sb); /* */ ++s; /* */ } while ( is_digit(*s) ); /* */ break; /* */ default: /* */ if ( is_space(*s) ) ++s; /* Ignore spaces. */ else if (!is_allowed(*s)) /* */ { PUTC(*s, sb); /* */ s++; /* */ } /* */ else /* Only macros are left. */ { String sym = (String)s; /* */ String val; /* */ Uchar c; /* */ /* */ DebugPrint2("Start symbol: ",s); /* */ while ( is_allowed(*s) ) ++s; /* */ c = *s; *s = '\0'; /* */ { String sym_copy = /* */ (String)malloc(strlen((char*)sym)+1);/* Copy of sym */ if (sym_copy == StringNULL ) /* Allocate memory */ { OUT_OF_MEMORY("expand string"); } /* Upon failure exit. */ (void)strcpy((char*)sym_copy,(char*)sym);/* Save sym */ *s = c; /* Restore end mark */ sym = symbol(sym_copy); /* Intern the symbol. */ free((char*)sym_copy); /* Free the temp. memory */ } /* */ val = db_string(db,sym,1); /* */ if ( val ) /* */ { brace = expand(val,sb,brace,first,q_open,q_close,db); }/* */ else /* */ { if ( !brace ) PUTS(q_close,sb); /* */ if ( !first ) PUTS(" # ",sb); /* */ PUTS(sym,sb); /* */ brace = TRUE; /* */ first = FALSE; /* */ } /* */ } /* */ } /* */ } /* */ return brace; /* */ } /*------------------------*/ BibTool/init.c0000644000175100017510000001104312646457161012152 0ustar genegene/*** init.c ******************************************************************* ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains the global initialization function which ** has to be called before any modules in \BibTool{} are ** activated. This is for convenience, thus nobody has to call ** the various initialization functions for the different modules ** by hand. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include "config.h" #ifdef HAVE_LIBKPATHSEA #ifdef __STDC__ #define HAVE_PROTOTYPES #endif #include #include #endif /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: init_bibtool() ** Purpose: Perform any initializations necessary for \BibTool. ** ** ** Arguments: ** progname Name of the program for |KPATHSEA|. ** Returns: nothing **___________________________________________________ */ void init_bibtool(progname) /* */ char * progname; /* */ { /* */ #ifdef EMTEX_LIKE_PATH static StringBuffer *sb_rsc; /* */ static StringBuffer *sb_bibtex; /* */ /* */ { char *emtexdir = getenv(EMTEXDIR); /* */ if ( emtexdir == NULL ) emtexdir = EMTEXTDIR_DEFAULT;/* */ sb_rsc = sbopen(); /* */ sbputs(".;",sb_rsc); /* */ sbputs(emtexdir,sb_rsc); /* */ sbputs(EMTEXT_RESOURCE,sb_rsc); /* */ rsc_v_rsc = sbflush(sb_rsc); /* */ sb_bibtex = sbopen(); /* */ sbputs(".;",sb_bibtex); /* */ sbputs(emtexdir,sb_bibtex); /* */ sbputs(EMTEXT_BIBTEX,sb_bibtex); /* */ rsc_v_bibtex = sbflush(sb_bibtex); /* */ } /* */ #endif /* */ POSSIBLY_UNUSED(progname); /* */ /* */ #ifdef HAVE_LIBKPATHSEA #ifdef HAVE_LIBKPATHSEA2 kpse_set_progname(progname); /* */ #else kpse_set_program_name(progname, "bibtool"); /* */ #endif #endif /* */ init_type(); /* */ init_symbols(); /* */ init_entries(); /* */ init_read(); /* */ /* */ set_rsc_path(rsc_v_rsc); /* */ /* */ init_macros(); /* */ init_read(); /* */ } /*------------------------*/ BibTool/key.c0000644000175100017510000032134712646457464012020 0ustar genegene/*** key.c ******************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_TIME_H #include #endif #include "config.h" /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String get_field _ARG((DB db,Record rec,String name));/* key.c */ String fmt_expand _ARG((StringBuffer *sb,String cp,DB db,Record rec));/* key.c*/ int apply_fmt _ARG((StringBuffer *sb,char *fmt,Record rec,DB db));/* key.c */ int foreach_ignored_word _ARG((int (*fct)_ARG((String))));/* key.c */ int mark_key _ARG((DB db,Record rec)); /* key.c */ int set_field _ARG((DB db,Record rec,String name,String value));/* key.c */ static KeyNode new_key_node _ARG((int type,String string));/* key.c */ static char * itostr _ARG((int i,char *digits)); /* key.c */ static int add_fmt_tree _ARG((char *s,KeyNode *treep));/* key.c */ static int deTeX _ARG((String line,void (*save_fct)_ARG((String)),int commap));/*key.c*/ static int eval__fmt _ARG((StringBuffer *sb,KeyNode kn,Record rec));/* key.c*/ static int eval_fmt _ARG((StringBuffer *sb,KeyNode kn,Record rec,DB db));/* key.c*/ static int fmt__parse _ARG((char **sp,KeyNode *knp));/* key.c */ static int fmt_c_names _ARG((String line,int min,int max,int not));/* key.c */ static int fmt_c_string _ARG((String s,int min,int max,int not));/* key.c */ static int fmt_c_words _ARG((String line,int min,int max,int not,int ignore));/* key.c*/ static int fmt_digits _ARG((StringBuffer *sb,String s,int mp,int pp,int n,int sel,int trunc));/* key.c*/ static int fmt_parse _ARG((char **sp,KeyNode *knp));/* key.c */ static void Push_Word _ARG((String s)); /* key.c */ static void eval__special _ARG((StringBuffer *sb,KeyNode kn,Record rec));/* key.c*/ static void fmt_names _ARG((StringBuffer *sb,String line,int maxname,int post,String trans));/* key.c*/ static void fmt_string _ARG((StringBuffer *sb,String s,int n,String trans,String sep));/* key.c*/ static void fmt_title _ARG((StringBuffer *sb,String line,int len,int in,String trans,int ignore,String sep));/* key.c*/ static void init_key _ARG((int state)); /* key.c */ static void key_init _ARG((void)); /* key.c */ static void push_s _ARG((StringBuffer *sb,String s,int max,String trans));/* key.c*/ static void push_word _ARG((String s)); /* key.c */ void add_format _ARG((char *s)); /* key.c */ void add_ignored_word _ARG((String s)); /* key.c */ void add_sort_format _ARG((char *s)); /* key.c */ void clear_ignored_words _ARG((void)); /* key.c */ void def_format_type _ARG((String s)); /* key.c */ void end_key_gen _ARG((void)); /* key.c */ void free_key_node _ARG((KeyNode kn)); /* key.c */ void make_key _ARG((DB db,Record rec)); /* key.c */ void make_sort_key _ARG((DB db,Record rec)); /* key.c */ void set_base _ARG((String value)); /* key.c */ void set_separator _ARG((int n,String s)); /* key.c */ void start_key_gen _ARG((void)); /* key.c */ #ifdef DEBUG static void show_fmt _ARG((KeyNode kn,int in)); /* key.c */ #endif /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ static DB tmp_key_db; /*---------------------------------------------------------------------------*/ #define KEYSTYLE_EMPTY 0x0010 #define KEYSTYLE_SHORT 0x0020 #define KEYSTYLE_LONG 0x0030 #define KEYSTYLE_EXTENDED 0x0040 static char *percent_chars = "NntTdDsSwWp"; /* */ #define DetexNone 0 #define DetexLower 1 #define DetexUpper 2 static StringBuffer *key_sb = (StringBuffer*)NULL;/* */ static StringBuffer *tmp_sb = (StringBuffer*)NULL;/* */ /*---------------------------------------------------------------------------*/ static KeyNode key_tree = (KeyNode)0; /* */ static KeyNode sort_key_tree = (KeyNode)0; /* */ static NameNode format[NUMBER_OF_FORMATS]; /* */ /*----------------------------------------------------------------------------- ** Variable*: formatp ** Type: int ** Purpose: Indicator variable which determines the state of ** |format|. It is set to |FALSE| as soon as |format| is ** initialized. **___________________________________________________ */ static int formatp = TRUE; /* */ #define SkipSpaces(CP) while ( is_space(*CP) ) ++(CP) #define SkipAllowed(CP) while ( is_allowed(*CP) ) ++(CP) #define ParseNumber(CP,N) if (is_digit(*CP)) { N = 0; \ while(is_digit(*CP) ){ N = N*10 + (*CP)-'0'; ++CP; }} #define Expect(CP,C,RET) SkipSpaces(CP); \ if ( *CP == C ) { ++(CP); } \ else { ErrPrintF("*** BibTool: Missing %c",C);\ return RET; } #define ExpectVoid(CP,C) SkipSpaces(CP); \ if ( *CP == C ) { ++(CP); } \ else { ErrPrintF("*** BibTool: Missing %c",C);\ return; } #define MakeNode(KNP,TYPE,SP,CP) c = *CP; *CP = '\0'; \ *KNP = new_key_node(TYPE,symbol((String)*SP));\ *CP = c; #define ParseOrReturn(CP,NODEP,MSG) \ if ( (ret=fmt_parse(CP,NODEP)) != 0 ) \ { DebugPrintF1(MSG); return ret; } /*****************************************************************************/ /*** Private word stack ***/ /*****************************************************************************/ static String *words = (String*)NULL; static size_t words_len = 0; static size_t words_used = 0; #define WordLenInc 16 #define PushWord(S) if(words_len>words_used) words[words_used++]=S; \ else Push_Word(S) #define ResetWords words_used = 0 /*----------------------------------------------------------------------------- ** Function: push_word() ** Purpose: Push a word to the stack. Wrapper function. ** Arguments: ** s word to push ** Returns: nothing **___________________________________________________ */ static void push_word(s) /* */ register String s; /* */ { PushWord(s); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: Push_Word() ** Purpose: Push a word to the stack when no space is left in the ** allocated array. ** Arguments: ** s word to push ** Returns: nothing **___________________________________________________ */ static void Push_Word(s) /* */ register String s; /* */ { register String *wp; /* */ /* */ words_len += WordLenInc; /* */ if ( words_len == WordLenInc ) /* */ { wp = (String*)malloc(words_len*sizeof(String)); }/* */ else /* */ { wp = (String*)realloc(words,words_len*sizeof(String)); }/* */ if ( wp == (String*)0 ) /* */ { words_len -= WordLenInc; /* */ ERROR((String)"Push_Word() failed: Word not pushed.");/* */ return; /* */ } /* */ /* */ words = wp; /* */ PushWord(s); /* */ } /*------------------------*/ /*****************************************************************************/ /*** Key Separator Section ***/ /*****************************************************************************/ #define NoSeps 8 static String key_seps[NoSeps] = { /* 0 */ (String)"**key*", /* 1 */ (String)"-", /* 2 */ (String)".", /* 3 */ (String)".", /* 4 */ (String)":", /* 5 */ (String)"-", /* 6 */ (String)"*", /* 7 */ (String)".ea" }; #define DefaultKey key_seps[0] #define InterNameSep key_seps[1] #define NamePreSep key_seps[2] #define NameNameSep key_seps[3] #define NameTitleSep key_seps[4] #define TitleTitleSep key_seps[5] #define KeyNumberSep key_seps[6] #define EtAl key_seps[7] /*----------------------------------------------------------------------------- ** Function: set_separator() ** Purpose: Modify the |key_seps| array. This array contains the ** different separators used during key formatting. The ** elements of the array have the following meaning: ** \begin{description} ** \item[0] The default key which is used when the ** formatting instruction fails completely. ** \item[1] The separator which is inserted between ** different names of a multi-authored publication. ** \item[2] The separator inserted between the first name ** and the last name when a name is formatted. ** \item[3] The separator inserted between the last names ** when more then one last name is present ** \item[4] The separator between the name and the title ** of a publication. ** \item[5] The separator inserted between words of the ** title. ** \item[6] The separator inserted before the number ** which might be added to disambiguate reference keys. ** \item[7] The string which is added when a list of ** names is truncated. (|.ea|) ** \end{description} ** Arguments: ** n Array index to modify. ** s New value for the given separator. The new value is ** stored as a symbol. Thus the memory of |s| need not to ** be preserved after this function is completed. ** The characters which are not allowed are silently sypressed. ** Returns: nothing **___________________________________________________ */ void set_separator(n,s) /* */ register int n; /* */ String s; /* */ { String t, tp; /* */ /* */ /* */ if ( n < 0 || n >= NoSeps ) /* */ { ERROR("Invalid separator specification."); /* */ return; /* */ } /* */ /* */ t = new_Ustring((char*)s); /* */ for ( tp = t; *s ; s++ ) /* */ { if ( is_allowed(*s) ) *tp++ = *s; } /* */ *tp = '\0'; /* */ /* */ ReleaseSymbol(key_seps[n]); /* */ key_seps[n] = symbol(t); /* */ free(t); /* */ switch (n) /* */ { case 1: init_key(1); break; case 2: init_key(2); break; } /* */ } /*------------------------*/ /*****************************************************************************/ /*** Key Base Section ***/ /*****************************************************************************/ static char * key__base[] = { "0123456789", "_abcdefghijklmnopqrstuvwxyz", "_ABCDEFGHIJKLMNOPQRSTUVWXYZ" }; #define KEY_BASE_DIGIT 0 #define KEY_BASE_LOWER 1 #define KEY_BASE_UPPER 2 static int key_base = KEY_BASE_DIGIT; /*----------------------------------------------------------------------------- ** Function: set_base() ** Purpose: Define the key base. This value determines the format ** of the disambiguation string added to a key if ** required. The following values are considered: ** \begin{itemize} ** \item If the value is |upper| or starts with an upper ** case letter then the disambiguation is done with ** upper-case letters. ** \item If the value is |lower| or starts with a lower ** case letter then the disambiguation is done with ** lower-case letters. ** \item If the value is |digit| or starts with an digit ** then the disambiguation is done with arabic numbers. ** \end{itemize} ** The comparison of the keywords is done case ** insensitive. The special values take precedence before ** the first character rules. ** ** If an invalid value is given to this function then an ** error is raised and the program is terminated. ** Arguments: ** value String representation of the new value. ** Returns: nothing **___________________________________________________ */ void set_base(value) /* */ String value; /* */ { /* */ if ( case_cmp(value,(String)"upper") ) key_base = KEY_BASE_UPPER;/* */ else if ( case_cmp(value,(String)"lower") ) key_base = KEY_BASE_LOWER;/* */ else if ( case_cmp(value,(String)"digit") ) key_base = KEY_BASE_DIGIT;/* */ else if ( is_upper(*value) ) key_base = KEY_BASE_UPPER;/* */ else if ( is_lower(*value) ) key_base = KEY_BASE_LOWER;/* */ else if ( is_digit(*value) ) key_base = KEY_BASE_DIGIT;/* */ else { ERROR("Unknown base ignored."); } /* */ } /*------------------------*/ #define ITOA_LEN 64 /*----------------------------------------------------------------------------- ** Function: itostr() ** Purpose: Translate number using the ``digits'' given. ** A static string is returned containing the result. ** This is a routine generalizing |itoa()|. ** Examples: ** itostr(X,"0123456789ABCDEF") returns the hexadecimal representation ** itostr(X,"0123456789") returns the decimal representation ** itostr(X,"01234567") returns the octal representation ** itostr(X,"01") returns the binary representation ** ** Arguments: ** i Integer to translate ** digits String of digits to use ** Returns: **___________________________________________________ */ static char * itostr(i,digits) /* */ register int i; /* */ register char *digits; /* */ { static char buffer[ITOA_LEN]; /* buffer to store result */ register char *bp; /* buffer pointer */ register int sign, /* */ base; /* */ /* */ base = strlen(digits); /* how many digits? */ bp = buffer+ITOA_LEN-1; /* set pointer to the end.*/ *(bp--) = '\0'; /* mark the end. */ if ( i<0 ) { sign = -1; i = -i; } /* */ else { sign = 0; if ( i == 0 ) *(bp--) = '0'; } /* */ while ( i > 0 ) /* */ { *(bp--) = digits[i%base]; /* */ i = i/base; /* */ } /* */ if ( sign ) *bp = '-'; else ++bp; /* */ return(bp); /* */ } /*------------------------*/ /*****************************************************************************/ /*** Key Init Section ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: init_key() ** Purpose: Global initializations for the key module. ** This function has to be called before some of the ** functions provided in this module are guaranteed to ** work properly. ** Arguments: ** state ** Returns: nothing **___________________________________________________ */ static void init_key(state) /* */ int state; /* */ { int i; /* */ String s; /* */ /* */ if ( formatp ) /* */ { /* */ for (i = 0; i < NUMBER_OF_FORMATS; i++) /* */ { format[i] = NameNULL; } /* */ formatp = FALSE; /* */ } /* */ /* */ if ( state & 1 ) /* */ { /* */ if ( format[0] == NameNULL ) /* */ { s = new_Ustring("%*l"); /* */ format[0] = name_format(s); /* */ free(s); /* */ } /* */ NameMid(format[0]) = InterNameSep; /* */ } /* */ /* */ if ( state & 2 ) /* */ { /* */ if ( format[1] == NameNULL ) /* */ { s = new_Ustring("%*l%*1f"); /* */ format[1] = name_format(s); /* */ free(s); /* */ } /* */ NameMid(format[1]) = InterNameSep; /* */ if (NextName(format[1])) /* */ { NamePre(NextName(format[1])) = NamePreSep; /* */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: key_init() ** Purpose: Perform initializations for key generation. ** The string buffer is opened. ** Ignored words are initialized if necessary. ** Arguments: none ** Returns: nothing **___________________________________________________ */ static void key_init() /* */ { /* */ #ifdef INITIALIZE_IGNORED_WORDS static char *word_list[] = /* default ignored words. */ { INITIALIZE_IGNORED_WORDS, NULL }; /* Mark the end with NULL */ register char**wp; /* */ #endif /* */ if ( key_sb == (StringBuffer*)0 ) /* Is it the first time? */ { /* */ if ( (key_sb=sbopen()) == (StringBuffer*)0 ) /* open string buffer */ { OUT_OF_MEMORY("key generation."); } /* */ #ifdef INITIALIZE_IGNORED_WORDS for ( wp = word_list; *wp != NULL; ++wp ) /* add ignored words. */ { add_ignored_word((String)*wp); } /* */ #endif } /* */ } /*------------------------*/ /*****************************************************************************/ /*** Key DeTeX Section ***/ /*****************************************************************************/ #define DeTeX_BUFF_LEN 256 #define DETEX_FLAG_NONE 0 #define DETEX_FLAG_COMMA 1 #define DETEX_FLAG_ALLOWED 2 /*----------------------------------------------------------------------------- ** Function: deTeX() ** Purpose: Expand TeX sequences or eliminate them. ** ** Arguments: ** line string to work on ** save_fct Function pointer which is called to store resulting ** characters. ** flags ** Returns: **___________________________________________________ */ static int deTeX(line,save_fct,flags) /* */ String line; /* */ int flags; /* */ void (*save_fct)_ARG((String)); /* */ { static String buffer; /* */ static size_t len = 0; /* */ Uchar c; /* */ String s, bp; /* */ Uchar last = (Uchar)' '; /* */ int wp = 0; /* */ int brace; /* */ /* */ #define SaveWord wp++; (*save_fct)(bp) #define SaveChar(C) *(bp++) = last = C #define StoreChar(C) *(bp++) = C /* */ brace = 8 * strlen((char*)line); /* */ if ( brace > (int)len ) /* */ { if ( len == 0 ) /* */ { len = ( brace < DeTeX_BUFF_LEN /* */ ? DeTeX_BUFF_LEN : brace ); /* */ buffer = (String)malloc(sizeof(Uchar)*len); /* */ } /* */ else /* */ { len = brace; /* */ buffer = (String)realloc((char*)buffer, /* */ sizeof(Uchar)*len); /* */ } /* */ if ( buffer == NULL ) /* */ { OUT_OF_MEMORY("deTeX()"); } /* */ } /* */ /* */ TeX_open_string(line); /* */ bp = buffer; /* */ brace = 0; /* */ wp = 0; /* */ SaveWord; /* */ /* */ while ( TeX_read(&c, &s) ) /* */ { /* */ if ( is_alpha(c) /* Letters and */ || is_digit(c) /* digits and */ || is_extended(c) /* extended chars and */ || ( c == (Uchar)'-' && last != c ) ) /* non-repeated hyphens */ { SaveChar(c); } /* */ else if ( c == (Uchar)'{' ) { ++brace; } /* Count braces. */ else if ( c == (Uchar)'}' ) /* */ { if ( --brace < 0 ) brace = 0; /* */ } /* */ else if ( ( c == ',' /* Commas */ && (flags&DETEX_FLAG_COMMA) ) /* */ || /* or */ ( (flags&DETEX_FLAG_ALLOWED) /* allowed characters */ && is_allowed(c) ) /* */ ) /* */ { if ( bp != buffer && *(bp-1) != '\0' ) /* are treated as */ { StoreChar('\0'); /* single words upon */ SaveWord; /* request, or ignored. */ } /* */ StoreChar(c); /* */ StoreChar('\0'); /* */ SaveWord; /* */ last = ' '; /* */ } /* */ else if ( !(flags&DETEX_FLAG_ALLOWED) /* */ && is_wordsep(c) /* */ && !is_wordsep(last) ) /* Don't repeat spaces. */ { if ( brace == 0 ) /* Remember the beginning */ { StoreChar('\0'); SaveWord; last = ' '; } /* of the next word. */ else /* */ { String t; /* */ for (t = InterNameSep; *t; ++t ) /* */ { SaveChar(*t); } /* */ } /* */ } /* */ } /* */ /* */ if (buffer) { /* */ if ( bp != buffer && *(bp-1) != '\0' ) /* */ { StoreChar('\0'); /* */ SaveWord; /* */ } /* */ /* */ StoreChar('\0'); /* Mark the end. */ /* */ if ( bp-buffer >= (int)len ) /* */ { ERROR_EXIT("deTeX buffer overflow."); } /* */ } /* */ /* */ TeX_close(); /* */ return wp-1; /* */ } /*------------------------*/ /*****************************************************************************/ /*** Title Formatting Section ***/ /*****************************************************************************/ #define PushS(SB,S) push_s(SB,S,0,trans) #define PushStr(SB,S,M) push_s(SB,S,M,trans) #define PushC(SB,C) (void)sbputchar(trans[(unsigned int)(C)],SB); /*----------------------------------------------------------------------------- ** Function: push_s() ** Purpose: Write a translated string to the key string buffer. ** Arguments: ** s String to translate ** max Maximum number of characters ** trans Translation table ** Returns: nothing **___________________________________________________ */ static void push_s(sb,s,max,trans) /* */ StringBuffer *sb; /* */ String s; /* */ int max; /* */ String trans; /* */ { /* */ if ( max <= 0 ) /* */ { while ( *s ) /* */ { (void)sbputchar(trans[*(s++)],sb); } /* */ } /* */ else /* */ { while ( *s && max-->0 ) /* */ { (void)sbputchar(trans[*(s++)],sb); } /* */ } /* */ } /*------------------------*/ static WordList ignored_words[32] = { WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL }; /*----------------------------------------------------------------------------- ** Function: add_ignored_word() ** Purpose: Add a new word to the list of ignored words for title ** key generation. ** The argument has to be saved by the caller! This means ** that it is assumed that the argument is a symbol. ** Arguments: ** word Word to add. ** Returns: nothing **___________________________________________________ */ void add_ignored_word(word) /* */ String word; /* */ { /* */ key_init(); /* */ add_word(word ,&ignored_words[(*word)&31]); /* */ DebugPrint2("Adding ignored word ", word); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: clear_ignored_words() ** Purpose: Delete the list of ignored words. Afterwards no words are ** recognized as ignored words. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void clear_ignored_words() /* */ { int i; /* */ key_init(); /* */ /* */ for (i = 0; i < 32; i++) /* */ { free_words(&ignored_words[i], NULL); } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: foreach_ignored_word() ** Purpose: Iterator a given function |fct| is applied to each ** ignored word in turn. If the function returns 0 then ** the loop is terminated. The different words are ** visited in a fixed order which does not necessarily ** coincide with the natural order of words. Thus don't ** assume this. ** Arguments: ** fct Function to apply. ** Returns: The return status of the last |fct| call. **___________________________________________________ */ int foreach_ignored_word(fct) /* */ int (*fct)_ARG((String)); /* */ { int i; /* */ /* */ key_init(); /* */ /* */ for (i = 0; i < 32; i++) /* */ { if (!foreach_word(ignored_words[i], fct)) /* */ { return 0; } /* */ } /* */ return 1; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt_title() ** Purpose: Format a string according to rules for titles. ** \TeX{} sequences are expanded and some words may be ignored. ** The result is pushed to the local string buffer. ** Arguments: ** line String to format. ** len Number of words to use ** in Number of characters per word to use ** trans Translation table ** ignore Boolean. Certain words are ignored if it is TRUE ** sep String separating the words. ** Returns: nothing **___________________________________________________ */ static void fmt_title(sb, line, len, in, trans, ignore, sep)/* */ StringBuffer *sb; /* */ String line; /* */ int len; /* */ int in; /* */ String trans; /* Translation table */ int ignore; /* */ String sep; /* */ { int first = TRUE; /* */ int nw, i, j; /* */ String s; /* */ /* */ /* if ( len == 0 ) return; */ /* */ if ( tmp_sb == (StringBuffer*)NULL /* */ && (tmp_sb=sbopen()) == (StringBuffer*)NULL )/* */ { OUT_OF_MEMORY("fmt_title()"); } /* */ /* */ ResetWords; /* */ nw = deTeX(*line == (Uchar)'{' ? line + 1 : line,/* */ push_word, /* */ DETEX_FLAG_NONE); /* */ /* */ for ( i = 0; i < nw; ++i ) /* */ { /* */ sbrewind(tmp_sb); /* Reset the string buffer*/ for ( s = words[i]; *s; ++s ) /* Translate the current */ { (void)sbputchar(trans[*s],tmp_sb); } /* word into the sbuffer */ s = (String)sbflush(tmp_sb); /* Get the translated word*/ /* */ if ( ! ignore || /* */ ! find_word((String)s,ignored_words[(*s)&31] ) )/* */ { if ( first ) { first = FALSE; } /* */ else { PushS(sb,sep); } /* */ if ( in <= 0 ) /* */ { PushS(sb, words[i]); } /* Push the current word */ else /* */ { for (s = words[i], j = in; *s && j-->0; ++s)/* Push the initial part */ { PushC(sb, *s); } /* of the current word. */ } /* */ if ( len == 1 ) return; /* */ if ( len > 0 ) len--; /* */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt_c_words() ** Purpose: Count a list of words. ** ** ** Arguments: ** line string to analyze ** min minimum ** max maximum or 0 ** not negation flag ** ignore flag to indicate if certain words should be ignored. ** Returns: **___________________________________________________ */ static int fmt_c_words(line, min, max, not, ignore)/* */ String line; /* */ int min; /* */ int max; /* */ int not; /* */ int ignore; /* */ { int n, i, nw; /* */ /* */ ResetWords; /* */ nw = deTeX(*line == (Uchar)'{' ? line + 1 : line,/* */ push_word, /* */ DETEX_FLAG_NONE); /* */ n = 0; /* */ /* */ for ( i = 0; i < nw; ++i ) /* */ { /* */ if ( !ignore || /* */ !find_word(words[i], /* */ ignored_words[(*words[i])&31]) )/* */ { n++; } /* */ } /* */ /* */ if ( n < min || (max > 0 && n > max)) /* */ { return (not ? FALSE : TRUE); } /* */ /* */ return (not ? TRUE : FALSE); /* */ } /*------------------------*/ /*****************************************************************************/ /*** Name Formatting Section ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: def_format_type() ** Purpose: ** ** ** Arguments: ** s ** Returns: nothing **___________________________________________________ */ void def_format_type(s) /* */ String s; /* */ { int n; /* */ String cp; /* */ Uchar c; /* */ /* */ SkipSpaces(s); /* */ n = 0; /* */ while ( is_digit(*s) ) { n = n*10 + (*s++) - '0'; }/* */ if ( n >= NUMBER_OF_FORMATS ) /* */ { WARNING("Format type number is out of range.");/* */ return; /* */ } /* */ if ( rsc_verbose && n <= 1 ) /* */ { VerbosePrint3("Name format specifier ", /* */ (n==0?"0":"1"), /* */ " has been changed.\n"); /* */ } /* */ /* */ if ( formatp ) { init_key(3); } /* */ /* */ SkipSpaces(s); /* */ if ( *s == '=' ) s++; /* */ ExpectVoid(s,'"'); /* */ cp = s; /* */ while ( *cp && *cp != '"' ) cp++; /* */ c = *cp; /* */ *cp = (Uchar)'\0'; /* */ format[n] = name_format(s); /* */ *cp = c; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt_names() ** Purpose: Format a list of names separated by 'and'. ** 'and others' is handled properly. ** Arguments: ** line String to format. ** maxname Number of names to consider ** maxlen Number of characters per name to consider ** trans Translation table ** Returns: nothing **___________________________________________________ */ static void fmt_names(sb,line,maxname,post,trans) /* */ StringBuffer *sb; /* */ String line; /* Name list string */ int maxname; /* number of names b4 etal*/ int post; /* number of relevant char*/ String trans; /* Translation table */ { int wp, /* */ i; /* */ static String and = (String)"&"; /* */ static String comma = (String)","; /* */ static int undef_warning = FALSE; /* */ /* */ if ( maxname == 0 ) return; /* */ /* */ if ( post < 0 /* */ || post >= NUMBER_OF_FORMATS /* */ || format[post] == NameNULL ) /* */ { if (undef_warning) /* */ { ErrPrintF("*** BibTool: Format %d is not defined. Ignored.\n",/* */ post); /* */ undef_warning = TRUE; /* */ } /* */ return; /* */ } /* */ /* */ ResetWords; /* */ wp = deTeX(*line == (Uchar)'{' ? line + 1 : line,/* */ push_word, /* */ DETEX_FLAG_COMMA); /* */ words[wp] = NULL; /* */ /* */ for (i = 0; i < wp; i++) /* */ { /* */ DebugPrintF3("+++ %3d '%s'\n", i, words[i]); /* */ /* */ if ( strcmp((char*)words[i],"and") == 0 ) /* */ { words[i] = and; } /* */ else if ( strcmp((char*)words[i],",") == 0 ) /* */ { words[i] = comma; } /* */ } /* */ /* */ PushS(sb,pp_list_of_names(words, /* */ format[post], /* */ trans, /* */ maxname, /* */ comma, /* */ and, /* */ (char*)NameNameSep, /* */ (char*)EtAl)); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt_c_names() ** Purpose: Count a list of names ** ** ** Arguments: ** line string to analyze ** min minimum ** max maximum or 0 ** not negation flag ** Returns: nothing **___________________________________________________ */ static int fmt_c_names(line,min,max,not) /* */ String line; /* Name list string */ int min; /* number of relevant char*/ int max; /* number of names b4 etal*/ int not; /* negation flag */ { int wp, /* */ i, /* */ n; /* */ /* */ ResetWords; /* */ wp = deTeX(*line == (Uchar)'{' ? line + 1 : line,/* */ push_word, /* */ DETEX_FLAG_COMMA); /* */ words[wp] = NULL; /* */ /* */ for ( i = 0, n = 1; i < wp; i++) /* */ { if ( strcmp((char*)words[i],"and") == 0 ) /* */ { n++; } /* */ } /* */ /* */ if ( n < min || (max > 0 && n > max)) /* */ { return (not ? FALSE : TRUE); } /* */ /* */ return (not ? TRUE : FALSE); /* */ } /*------------------------*/ /*****************************************************************************/ /*** Number Formatting Section ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: fmt_digits() ** Purpose: Search a sequence of digits and push at most n of them ** counting from right to the string buffer. ** Example: fmt_digits("jun 1958",2) pushes "58" to the string buffer. ** Arguments: ** sb String buffer to store the result in ** s String to format ** mp Boolean indicating whether padding with 0s should be performed ** (true) or not. ** pp Boolean indicating whether no number should be 0 or fail ** n Length ** sel The number to select. ** trunc Boolean indicating whether or not to truncate the number. ** Returns: nothing **___________________________________________________ */ static int fmt_digits(sb,s,mp,pp,n,sel,trunc) /* */ StringBuffer *sb; /* */ register String s; /* */ int mp; /* */ int pp; /* */ register int n; /* */ int sel; /* */ int trunc; /* */ { register String cp; /* */ /* */ if ( n < 0 ) { n = ( mp ? 1 : 0x7fff ); } /* */ /* */ cp = s; /* */ while ( sel-->0 ) /* */ { s = cp; /* */ while( *s && !is_digit(*s) ) { ++s; } /* search first digit */ if ( *s == '\0' ) /* */ { cp = s; sel = 0; } /* */ else /* */ { for ( cp = s; *cp && is_digit(*cp); ++cp) {} /* skip over digits */ } /* */ } /* */ /* */ if ( trunc && cp-s > n ) s = cp-n; /* */ else if ( mp ) /* */ { while ( cp-s < n-- ) /* */ { (void)sbputchar('0', sb); } /* */ } /* */ if ( !mp && *s == '\0' ) /* */ { if ( pp ) (void)sbputchar('0', sb); /* */ else return 1; /* */ } /* */ else /* */ { /* */ while ( s != cp ) /* */ { (void)sbputchar((char)(*s), sb); /* */ ++s; /* */ } /* */ } /* */ return 0; /* */ } /*------------------------*/ /*****************************************************************************/ /*** String Formatting Section ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: fmt_string() ** Purpose: Push characters from s onto the string buffer. ** At most n characters are transfered. ** Letters are translated according to mode. ** Arguments: ** s String to format ** n Length ** trans Translation table ** sep Separator ** Returns: nothing **___________________________________________________ */ static void fmt_string(sb,s,n,trans,sep) /* */ StringBuffer *sb; /* */ register String s; /* */ register int n; /* */ register String trans; /* */ String sep; /* */ { /* */ while ( *s && n > 0 ) /* */ { if ( is_allowed(*s) ) /* */ { (void)sbputchar(trans[*s],sb); /* */ n--; /* */ } /* */ else if ( is_space(*s) ) /* */ { (void)sbputs((char*)sep, sb); /* */ n--; /* */ while ( is_space(*s) ) s++; /* skip over multiple SPC */ s--; /* */ } /* */ ++s; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt_c_string() ** Purpose: Count the number of characters in a string and compare it ** against an interval. ** ** Arguments: ** s string to analyze ** min minimum ** max maximum or 0 ** not negation flag ** Returns: **___________________________________________________ */ static int fmt_c_string(s,min,max,not) /* */ register String s; /* */ register int min; /* */ register int max; /* */ register int not; /* */ { int n = 0; /* */ /* */ while ( *s ) /* */ { if ( is_allowed(*s) ) { n++; } /* */ else if ( is_space(*s) ) /* */ { n += strlen((char*)TitleTitleSep); /* */ while ( is_space(*s) ) s++; /* skip over multiple SPC */ } /* */ ++s; /* */ } /* */ /* */ if ( n < min || (max > 0 && n > max)) /* */ { return (not ? FALSE : TRUE); } /* */ /* */ return (not ? TRUE : FALSE); /* */ } /*------------------------*/ #define IfGetField(S,NAME) if((S=get_field(tmp_key_db,rec,NAME))!=NULL) #define GetEntryOrReturn(S,NAME) \ if((S=get_field(tmp_key_db,rec,NAME))==NULL) return(FALSE) static WordList old_keys = WordNULL; static Record tmp_rec = NULL; /*----------------------------------------------------------------------------- ** Function: start_key_gen() ** Purpose: Start the key generation. ** Any recorded keys are discarded. ** Arguments: ** Returns: nothing **___________________________________________________ */ void start_key_gen() /* */ { /* */ free_words(&old_keys, sym_unlink); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: end_key_gen() ** Purpose: Finalize the key generation. ** Any previously recorded keys are discarded. ** Arguments: ** Returns: nothing **___________________________________________________ */ void end_key_gen() /* */ { /* */ free_words(&old_keys,sym_unlink); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: mark_key() ** Purpose: Set the key mark for the key symbol of a record. ** Arguments: ** db Database containing the record. ** rec Record to consider ** Returns: nothing **___________________________________________________ */ int mark_key(db,rec) /* */ DB db; /* */ Record rec; /* */ { /* */ POSSIBLY_UNUSED(db); /* */ /* */ if ( IsSpecialRecord(RecordType(rec)) || /* */ *RecordHeap(rec) == NULL ) /* */ { return 0; } /* */ /* */ add_word(symbol(*RecordHeap(rec)),&old_keys); /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: make_key() ** Purpose: Generate a key for a given record. ** Arguments: ** db Database containing the record. ** rec Record to consider. ** Returns: nothing **___________________________________________________ */ void make_key(db,rec) /* */ DB db; /* */ register Record rec; /* */ { register String kp; /* */ String old; /* */ int pos; /* */ /* */ if ( IsSpecialRecord(RecordType(rec)) ) return; /* */ /* */ if ( key_tree == (KeyNode)0 ) /* */ { *RecordHeap(rec) = sym_empty; /* store an empty key */ return; /* */ } /* */ /* */ if ( formatp ) { init_key(3); } /* */ /* */ if ( rsc_key_preserve && /* */ **RecordHeap(rec) != '\0' ) /* */ { return; } /* */ /* */ key_init(); /* */ sbrewind(key_sb); /* clear key */ /* */ if ( eval_fmt(key_sb,key_tree,rec,db) ) /* */ { sbputs((char*)DefaultKey,key_sb); /* */ } /* */ /* */ ReleaseSymbol(RecordOldKey(rec)); /* */ RecordOldKey(rec) = *RecordHeap(rec); /* save old key */ #ifndef NEW #define trans trans_id ResetWords; /* */ { char * buffer = new_string(sbflush(key_sb)); /* */ int nw = deTeX((String)(*buffer == '{' /* */ ? buffer + 1 /* */ : buffer), /* */ push_word, /* */ DETEX_FLAG_ALLOWED); /* */ int i; /* */ sbrewind(key_sb); /* */ for ( i = 0; i < nw; ++i ) /* */ { if ( strcmp((char*)words[i], "\\") ) /* */ PushS(key_sb, words[i]); /* */ } /* */ free(buffer); /* */ } /* */ #undef trans #endif pos = sbtell(key_sb); /* */ kp = (String)sbflush(key_sb); /* get collected key */ /* */ if ( find_word(kp,old_keys) ) /* is key already used? */ { int n = 1; /* Then disambiguate: */ (void)sbseek(key_sb,pos); /* */ (void)sbputs((char*)KeyNumberSep,key_sb); /* put separator at end */ pos = sbtell(key_sb); /* */ do /* last symbol was present*/ { (void)sbseek(key_sb,pos); /* */ (void)sbputs(itostr(n++,key__base[key_base]),/* */ key_sb); /* */ kp = (String)sbflush(key_sb); /* get new key */ } while ( find_word(kp,old_keys) ); /* */ } /* */ /* */ kp = symbol(kp); /* */ old = *RecordHeap(rec); /* */ *RecordHeap(rec) = kp; /* store new key */ add_word(kp,&old_keys); /* remember new key */ /* ---------------------- */ if (rsc_make_alias /* if needed then make */ && !rsc_apply_alias /* */ && old != NULL /* an alias */ && kp != old /* */ && *old) /* */ { /* */ if (tmp_rec == RecordNULL) /* lacy initialization */ { tmp_rec = new_record(BIB_ALIAS,2); } /* */ /* */ *RecordHeap(tmp_rec) = old; /* */ RecordHeap(tmp_rec)[1] = kp; /* */ db_insert(db,copy_record(tmp_rec),FALSE); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: make_sort_key() ** Purpose: ** ** Arguments: ** db Database containing the record. ** rec Record to consider. ** Returns: nothing **___________________________________________________ */ void make_sort_key(db,rec) /* */ DB db; /* */ register Record rec; /* */ { register String kp; /* */ /* */ if ( IsSpecialRecord(RecordType(rec)) ) return; /* */ /* */ key_init(); /* */ sbrewind(key_sb); /* clear key */ /* */ if ( sort_key_tree != (KeyNode)0 /* */ && eval_fmt(key_sb,sort_key_tree,rec,db) == 0 )/* */ { kp = (String)sbflush(key_sb); /* get collected key */ RecordSortkey(rec) = symbol(kp); /* store new key */ } /* */ else /* If everything fails */ { RecordSortkey(rec) = RecordHeap(rec)[0]; /* use the reference key */ } /* */ } /*------------------------*/ /*****************************************************************************/ /*** Key Format Parsing and Evaluating ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: new_key_node() ** Purpose: Allocate a new key node ** Arguments: ** type ** string ** Returns: The address of the new node. ** Upon failure exit() is called. **___________________________________________________ */ static KeyNode new_key_node(type, string) /* */ int type; /* */ String string; /* */ { KeyNode new; /* */ if( (new=(KeyNode)malloc(sizeof(SKeyNode))) == (KeyNode)0 )/* */ { OUT_OF_MEMORY(" new_key_node()"); } /* */ /* */ NodeType(new) = type; /* */ NodeSymbol(new) = string; /* */ NodeNext(new) = (KeyNode)0; /* */ NodeThen(new) = (KeyNode)0; /* */ NodeElse(new) = (KeyNode)0; /* */ NodePre(new) = -1; /* */ NodePost(new) = -1; /* */ return new; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_key_node() ** Purpose: A tree rooted at a given |KeyNode| will be freed. ** ** Arguments: ** kn KeyNode to be freed. ** Returns: nothing **___________________________________________________ */ void free_key_node(kn) /* */ KeyNode kn; /* */ { KeyNode next; /* */ /* */ while ( kn != (KeyNode)0 ) /* */ { /* */ free_key_node(NodeThen(kn)); /* */ free_key_node(NodeElse(kn)); /* */ next = NodeNext(kn); /* */ free(kn); /* */ kn = next; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: add_fmt_tree() ** Purpose: Extend the format tree ** ** Arguments: ** s ** treep ** Returns: **___________________________________________________ */ static int add_fmt_tree(s, treep) /* */ char *s; /* */ KeyNode *treep; /* */ { KeyNode kn, kn_or; /* */ int special = 0; /* */ String s0 = (String )s; /* */ /* */ if ( s == (char*)NULL ) return FALSE; /* */ /* */ if ( strcmp(s,"empty") == 0 ) /* */ { free_key_node(*treep); /* */ *treep = (KeyNode)0; /* */ return TRUE; /* */ } /* */ else if ( strcmp(s,"short" ) == 0 ) /* */ { special = KEYSTYLE_SHORT; } /* */ else if ( strcmp(s,"long" ) == 0 ) /* */ { special = KEYSTYLE_LONG; } /* */ else if ( strcmp(s,"new.short") == 0 || /* */ strcmp(s,"short.need") == 0 ) /* */ { special = KEYSTYLE_SHORT; /* */ rsc_key_preserve = TRUE; /* */ } /* */ else if ( strcmp(s,"new.long" ) == 0 || /* */ strcmp(s,"long.need") == 0 ) /* */ { special = KEYSTYLE_LONG; /* */ rsc_key_preserve = TRUE; /* */ } /* */ /* */ if ( special ) /* */ { free_key_node(*treep); /* */ *treep = new_key_node(NodeSPECIAL,StringNULL); /* */ NodePre(*treep) = special; /* */ return TRUE; /* */ } /* */ /* */ if ( fmt_parse(&s,&kn) > 0 ) /* */ { error(ERR_POINT|ERR_WARN, /* */ (String)"Format Error. Format ignored.", /* */ StringNULL,StringNULL,s0,(String)s,0,(char*)sym_empty);/* */ return FALSE; /* */ } /* */ if ( *treep == (KeyNode)0 ) { *treep = kn; } /* */ else if ( NodeType(*treep) == NodeSPECIAL ) /* */ { free_key_node(*treep); /* */ *treep = kn; /* */ } /* */ else /* */ { kn_or = new_key_node(NodeOR,StringNULL); /* */ NodeThen(kn_or) = *treep; /* */ NodeElse(kn_or) = kn; /* */ *treep = kn_or; /* */ } /* */ /* */ #ifdef DEBUG show_fmt(*treep,0); /* */ #endif return TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: add_format() ** Purpose: Add a key format specification to the current ** specification. This specification is used for ** generating new reference keys. Thus the resource ** |rsc_make_key| is turned on aswell. ** ** Several strings are treated special. If a special ** format is encountered then the effect is that the old ** key specification is cleared first before the new ** format is added: ** \begin{description} ** \item[empty] The empty format is activated. This means that ** the format is cleared and without further action the ** default key will be used. ** \item[long] The long format is activated. This means that ** authors names with initials and the first word of ** the title are used. ** \item[short] The short format is activated. This means that ** authors last names and the first word of the title ** are used. ** \item[new.long] This means that the long format will ** be used but only if the record does not have a key ** already. ** \item[new.short] This means that the short format will ** be used but only if the record does not have a key ** already. ** \end{description} ** Arguments: ** s Specification string ** Returns: nothing **___________________________________________________ */ void add_format(s) /* */ register char *s; /* */ { /* */ if ( s == NULL ) /* */ { WARNING("Missing key format."); /* */ return; /* */ } /* */ rsc_make_key = TRUE; /* */ (void)add_fmt_tree(s,&key_tree); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: add_sort_format() ** Purpose: Add a sort key format specification to the current ** specification. This specification is used for ** generating new sort keys. ** ** Several strings are treated special. If a special ** format is encountered then the effect is that the old ** key specification is cleared first before the new ** format is added: ** \begin{description} ** \item[empty] The empty format is activated. This means that ** the format is cleared and without further action the ** default key will be used. ** \item[long] The long format is activated. This means that ** authors names with initials and the first word of ** the title are used. ** \item[short] The short format is activated. This means that ** authors last names and the first word of the title ** are used. ** \item[new.long] This means that the long format will ** be used but only if the record does not have a key ** already. ** \item[new.short] This means that the short format will ** be used but only if the record does not have a key ** already. ** \end{description} ** Arguments: ** s Specification string ** Returns: nothing **___________________________________________________ */ void add_sort_format(s) /* */ register char *s; /* */ { /* */ if ( s == NULL ) /* */ { WARNING("Missing sort key format."); /* */ return; /* */ } /* */ (void)add_fmt_tree(s,&sort_key_tree); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt_parse() ** Purpose: Parse the format specification given in the string *sp. ** Store the resulting KeyNode tree in *knp. ** *sp is modified to point to the first character not used. ** The return value is 0 iff no problem has been detected. ** Arguments: ** sp ** knp ** Returns: Error code. 0 = success **___________________________________________________ */ static int fmt_parse(sp,knp) /* */ char **sp; /* */ KeyNode *knp; /* */ { int ret; /* */ KeyNode new; /* */ /* */ *knp = (KeyNode)NULL; /* */ /* */ while ( (ret=fmt__parse(sp,knp)) == 0 ) /* */ { SkipSpaces(*sp); /* */ if ( **sp == '#' ) /* */ { new = new_key_node(NodeOR,StringNULL); /* */ NodeThen(new) = *knp; /* */ *knp = new; /* */ knp = &NodeElse(new); /* */ (*sp)++; /* */ } /* */ else return 0; /* */ } /* */ DebugPrintF1("<-format"); /* */ return ret; /* return the error code. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt__parse() ** Purpose: ** ** Arguments: ** sp Pointer to the string to be parsed ** knp Pointer to the key node in which to store the result ** Returns: Error code or 0 upon success **___________________________________________________ */ static int fmt__parse(sp,knp) /* */ char **sp; /* */ KeyNode *knp; /* */ { register char *cp; /* */ char c; /* */ int ret; /* */ /* */ cp = *sp; /* */ /* */ while ( *cp != '\0' ) /* */ { /* */ switch ( *cp ) /* */ { case ' ' : case '\t': case '\r': /* Skip over spaces. */ case '\n': case '\f': case '\b': /* */ cp++; break; /* */ case '#': /* Two cases evaluated */ case '}': return 0; /* somewhere else. */ case '%': /* Format specification: */ { int pre = -1, /* */ post = -1, /* %[-][0-9]*[.[0-9]*[a-Z]*/ type = 0; /* ([a-Z]*) */ switch ( *++cp ) /* */ { case '+': type = NodePlusMask; ++cp; break;/* */ case '-': type = NodeMinusMask; ++cp; break;/* */ } /* */ ParseNumber(cp,pre); /* */ if ( *cp == '.' || *cp == ',' || *cp == '-' )/* */ { cp++; /* */ ParseNumber(cp,post); /* */ } /* */ if ( *cp == '#' ) /* */ { cp++; /* */ type |= NodeCountMask; /* */ } /* */ if ( !is_alpha(*cp) ) /* */ { ErrPrintF("*** BibTool: Missing format type before: %s",cp);/* */ *sp = cp; /* */ DebugPrintF1("<-or"); /* */ return 1; /* */ } /* */ if ( strchr(percent_chars,*cp) == (char*)0 )/* */ { ErrPrintF("*** BibTool: Illegal format character: %c",*cp);/* */ *sp = cp; /* */ DebugPrintF1("<-percent"); /* */ return 1; /* */ } /* */ type |= *(cp++); /* */ Expect(cp,'(',1); /* */ SkipSpaces(cp); /* */ *sp = cp; /* */ SkipAllowed(cp); /* */ MakeNode(knp,type,sp,cp) /* */ NodePre(*knp) = pre; /* */ NodePost(*knp) = post; /* */ SkipSpaces(cp); /* */ Expect(cp,')',1); /* */ *sp = cp; /* */ knp = & NodeNext(*knp); /* */ } /* */ break; /* */ /* */ case '(': /* */ cp = (*sp)+1; /* */ SkipSpaces(cp); /* */ *sp = cp; /* */ SkipAllowed(cp); /* */ MakeNode(knp,NodeTEST,sp,cp); /* */ Expect(cp,')',1); /* */ Expect(cp,'{',1); /* */ *sp = cp; /* */ ParseOrReturn(sp,&NodeThen(*knp),"<-then");/* */ Expect(*sp,'}',1); /* */ Expect(*sp,'{',1); /* */ ParseOrReturn(sp,&NodeElse(*knp),"<-else");/* */ Expect(*sp,'}',1); /* */ knp = & NodeNext(*knp); /* */ cp = *sp; /* */ break; /* */ /* */ case '{': /* */ DebugPrintF1("--- parse block\n"); /* */ cp++; /* */ SkipSpaces(cp); /* */ *sp = cp; /* */ ParseOrReturn(sp,knp,"<-block"); /* */ Expect(*sp,'}',1); /* */ knp = & NodeNext(*knp); /* */ cp = *sp; /* */ break; /* */ /* */ default: /* */ *sp = cp; /* */ if ( is_allowed(*cp) ) /* */ { /* */ while ( is_allowed(*cp) ) { ++cp; } /* */ MakeNode(knp,NodeSTRING,sp,cp); /* */ *sp = cp; /* */ knp = & NodeNext(*knp); /* */ } /* */ else /* */ { ERROR2("Parse format. Illegal character ignored: ",cp);/* */ ++cp; /* */ } /* */ } /* */ } /* */ DebugPrintF1("<-fmt"); /* */ return -1; /* Signal end-of-string. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: eval_fmt() ** Purpose: Evaluate the given KeyNode tree w.r.t. the given Record. ** ** ** Arguments: ** kn ** rec ** db ** Returns: 0 upon success. **___________________________________________________ */ static int eval_fmt(sb,kn,rec,db) /* */ StringBuffer *sb; /* */ KeyNode kn; /* */ Record rec; /* */ DB db; /* */ { int pos = sbtell(sb); /* */ /* */ tmp_key_db = db; /* */ if ( eval__fmt(sb,kn,rec) != 0 ) /* */ { (void)sbseek(sb,pos); return 1; } /* */ /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: eval__fmt() ** Purpose: Evaluate the given KeyNode tree w.r.t. the given Record ** Internal version. trash of conjunctions is not removed. ** Arguments: ** sb ** kn ** rec ** Returns: **___________________________________________________ */ static int eval__fmt(sb,kn,rec) /* */ StringBuffer *sb; /* */ KeyNode kn; /* */ Record rec; /* */ { String s; /* */ int pos; /* */ String trans; /* */ /* */ DebugPrint1("eval__fmt()"); /* */ while ( kn != (KeyNode)0 ) /* */ { /* */ switch ( NodeType(kn) ) /* */ { case NodeSTRING: /* */ DebugPrint3("STRING \"",NodeSymbol(kn),"\"");/* */ (void)sbputs((char*)NodeSymbol(kn),sb); /* */ break; /* */ case NodeTEST: /* */ #ifdef DEBUG DebugPrint3("IF_THEN_ELSE (",NodeSymbol(kn),")");/* */ IfGetField(s,NodeSymbol(kn)) /* */ DebugPrint1("Field found. Continuing with THEN part");/* */ else DebugPrint1("Field NOT found. Continuing with ELSE part");/* */ #endif IfGetField(s,NodeSymbol(kn)) /* */ { (void)eval__fmt(sb,NodeThen(kn),rec); } /* */ else /* */ { (void)eval__fmt(sb,NodeElse(kn),rec); } /* */ break; /* */ /* */ case NodeOR: /* */ DebugPrint1("OR Trying THEN part"); /* */ pos = sbtell(sb); /* */ if ( eval__fmt(sb,NodeThen(kn),rec) != 0 ) /* */ { (void)sbseek(sb,pos); /* */ DebugPrint1("OR THEN part failed. Trying ELSE part.");/* */ if ( eval__fmt(sb,NodeElse(kn),rec) != 0 )/* */ { (void)sbseek(sb,pos); /* */ DebugPrint1("OR ELSE part failed"); /* */ return 1; /* */ } /* */ DebugPrint1("OR ELSE part succeeded"); /* */ } /* */ break; /* */ /* */ case NodeSPECIAL: /* */ eval__special(sb,kn,rec); /* */ break; /* */ default: /* */ #ifdef DEBUG fprintf(err_file,"+++ BibTool: FORMAT %s%d.%d%s%c(%s)\n",/* */ (NodeType(kn)&NodePlusMask /* */ ? "+" /* */ :(NodeType(kn)&NodeMinusMask /* */ ?"-":"")), /* */ NodePre(kn), /* */ NodePost(kn), /* */ (NodeType(kn)&NodeCountMask?"#":""),/* */ NodeType(kn)&0xff, /* */ NodeSymbol(kn)); /* */ #endif IfGetField(s,NodeSymbol(kn)) /* */ { /* */ DebugPrint1("Field found"); /* */ /* */ if (NodeType(kn)&NodeMinusMask) /* */ { trans = trans_lower; } /* */ else if (NodeType(kn)&NodePlusMask) /* */ { trans = trans_upper; } /* */ else /* */ { trans = trans_id; } /* */ #define UsePostOr(X) (NodePost(kn) > 0 ? NodePost(kn) : (X)) #define UsePreOr(X) (NodePre(kn) >= 0 ? NodePre(kn) : (X)) #define HasMinus (NodeType(kn)&NodeMinusMask) #define HasPlus (NodeType(kn)&NodePlusMask) /* */ switch ( NodeType(kn) & 0x1ff ) /* */ { /* */ case 'p': /* */ fmt_names(sb,s,UsePreOr(2),UsePostOr(0),trans);/* */ break; /* */ case 'n': /* */ if ( formatp ) init_key(3); /* */ NameStrip(format[0]) = UsePostOr(-1);/* */ fmt_names(sb,s,UsePreOr(2),0,trans); /* */ break; /* */ case 'N': /* */ if ( formatp ) init_key(3); /* */ NameStrip(format[1]) = UsePostOr(-1);/* */ if (NextName(format[1])) /* */ { NamePre(NextName(format[1])) = NamePreSep;/* */ } /* */ fmt_names(sb,s,UsePreOr(2),1,trans); /* */ break; /* */ case 'T': /* */ fmt_title(sb, /* */ s, /* */ UsePreOr(1), /* */ UsePostOr(0), /* */ trans, /* */ TRUE, /* */ TitleTitleSep); /* */ break; /* */ case 't': /* */ fmt_title(sb, /* */ s, /* */ UsePreOr(1), /* */ UsePostOr(0), /* */ trans, /* */ FALSE, /* */ TitleTitleSep); /* */ break; /* */ case 'd': /* */ if ( fmt_digits(sb, /* */ s, /* */ HasMinus, /* */ HasPlus, /* */ NodePre(kn), /* */ UsePostOr(1), /* */ TRUE) ) /* */ { return 1; } /* */ break; /* */ case 'D': /* */ if ( fmt_digits(sb, /* */ s, /* */ HasMinus, /* */ HasPlus, /* */ NodePre(kn), /* */ UsePostOr(1), /* */ FALSE) ) /* */ { return 1; } /* */ break; /* */ case 's': /* */ fmt_string(sb, /* */ s, /* */ UsePreOr(0xffff), /* */ trans, /* */ TitleTitleSep); /* */ break; /* */ case 'W': /* */ fmt_title(sb, /* */ s, /* */ UsePreOr(1), /* */ UsePostOr(0), /* */ trans, /* */ TRUE, /* */ sym_empty); /* */ break; /* */ case 'w': /* */ fmt_title(sb, /* */ s, /* */ UsePreOr(1), /* */ UsePostOr(0), /* */ trans, /* */ FALSE, /* */ sym_empty); /* */ break; /* */ case 'p' | NodeCountMask: /* */ case 'n' | NodeCountMask: /* */ case 'N' | NodeCountMask: /* */ if (fmt_c_names(s, /* */ UsePreOr(0), /* */ UsePostOr(0), /* */ HasMinus)) /* */ { return 1; } /* */ break; /* */ case 'd' | NodeCountMask: /* */ case 's' | NodeCountMask: /* */ if (fmt_c_string(s, /* */ UsePreOr(0), /* */ UsePostOr(0), /* */ HasMinus)) /* */ { return 1; } /* */ break; /* */ case 'T' | NodeCountMask: /* */ case 'W' | NodeCountMask: /* */ if (fmt_c_words(s, /* */ UsePreOr(0), /* */ UsePostOr(0), /* */ HasMinus, /* */ TRUE)) /* */ { return 1; } /* */ break; /* */ case 't' | NodeCountMask: /* */ case 'w' | NodeCountMask: /* */ if (fmt_c_words(s, /* */ UsePreOr(0), /* */ UsePostOr(0), /* */ HasMinus, /* */ FALSE)) /* */ { return 1; } /* */ break; /* */ default: return 1; /* */ } /* */ } /* */ else /* */ { /* */ DebugPrint1("Field not found"); /* */ return 1; /* */ } /* */ } /* */ kn = NodeNext(kn); /* */ } /* */ #undef UsePostOr #undef UsePreOr #undef HasMinus #undef HasPlus return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: eval__special() ** Purpose: ** ** Arguments: ** kn ** rec ** Returns: nothing **___________________________________________________ */ static void eval__special(sb,kn,rec) /* */ StringBuffer *sb; /* */ KeyNode kn; /* */ Record rec; /* */ { String s; /* */ int missing = TRUE, /* */ fmt; /* */ static String s_author = StringNULL; /* */ static String s_editor = StringNULL; /* */ static String s_title = StringNULL; /* */ static String s_booktitle = StringNULL; /* */ static String s_key = StringNULL; /* */ /* */ if ( s_author == StringNULL ) /* */ { s_author = sym_add((String)"author",-1); /* */ s_editor = sym_add((String)"editor",-1); /* */ s_title = sym_add((String)"title",-1); /* */ s_booktitle = sym_add((String)"booktitle",-1); /* */ s_key = sym_add((String)"key",-1); /* */ } /* */ /* */ if ( formatp ) init_key(3); /* */ fmt = ( NodePre(kn) == KEYSTYLE_LONG ? 1 : 0 ); /* */ NameStrip(format[fmt]) = NodePost(kn); /* */ /* */ IfGetField(s,s_author) /* */ { fmt_names(sb,s,2,fmt,trans_lower); /* */ missing = FALSE; /* */ } /* */ else IfGetField(s,s_editor) /* */ { fmt_names(sb,s,2,fmt,trans_lower); /* */ missing = FALSE; /* */ } /* */ /* */ IfGetField(s,s_title) /* */ { (void)sbputs((char*)NameTitleSep,sb); /* */ fmt_title(sb,s,1,0,trans_lower,TRUE,TitleTitleSep);/* */ missing = FALSE; /* */ } /* */ else IfGetField(s,s_booktitle) /* */ { (void)sbputs((char*)NameTitleSep,sb); /* */ fmt_title(sb,s,1,0,trans_lower,TRUE,TitleTitleSep);/* */ missing = FALSE; /* */ } /* */ /* */ if ( missing ) /* */ { sbrewind(sb); /* */ IfGetField(s,s_key) /* */ { fmt_title(sb,s,1,0,trans_lower,TRUE,TitleTitleSep); }/* */ else { (void)sbputs((char*)DefaultKey,sb); } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: apply_fmt() ** Purpose: Expands an arbitrary format specification for a given record. ** The format specification is given as a string. ** The result is stored in a string buffer. ** Arguments: ** sb Destination string buffer. ** fmt Format specification, ** rec Record to consider. ** db Database containing |rec|. ** Returns: |1| iff the format is invalid or the evaluation fails. |0| ** otherwise. **___________________________________________________ */ int apply_fmt(sb,fmt,rec,db) /* */ StringBuffer *sb; /* */ char *fmt; /* */ Record rec; /* */ DB db; /* */ { static char *old_fmt = NULL; /* */ static KeyNode old_kn = (KeyNode)0; /* */ /* */ if ( old_fmt == NULL /* This is the first time */ || strcmp(fmt,old_fmt) != 0 ) /* or the format needs */ { /* recompilation. */ key_init(); /* */ if ( old_fmt != NULL ) /* */ { free(old_fmt); /* */ free_key_node(old_kn); /* */ old_kn = (KeyNode)0; /* */ } /* */ /* */ old_fmt = new_string(fmt); /* */ if ( !add_fmt_tree(old_fmt,&old_kn) ) /* */ { free(old_fmt); /* */ old_fmt = NULL; /* */ return 1; /* */ } /* */ } /* */ return eval_fmt(sb,old_kn,rec,db); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fmt_expand() ** Purpose: Expands a format specification of the % type into a given ** string buffer. ** ** Arguments: ** sb destination string buffer ** cp format ** Returns: The first character after the % format. **___________________________________________________ */ String fmt_expand(sb,cp,db,rec) /* */ StringBuffer *sb; /* */ Uchar *cp; /* */ DB db; /* */ Record rec; /* */ { String field; /* */ String sp; /* */ Uchar c; /* */ String trans = trans_id; /* */ int pre = -1, /* */ post = -1, /* */ type = 0; /* */ /* */ while ( *cp && *cp != (Uchar)'%' ) /* */ { sbputchar((Uchar)*cp,sb); /* */ cp++; /* */ } /* */ /* */ if ( *cp == (Uchar)'%' ) /* */ { /* */ switch ( *++cp ) /* */ { case '+': trans = trans_upper; ++cp; break; /* */ case '-': trans = trans_lower; ++cp; break; /* */ } /* */ ParseNumber(cp,pre); /* */ if ( *cp == '.' || *cp == ',' || *cp == '-' ) /* */ { cp++; /* */ ParseNumber(cp,post); /* */ } /* */ if ( *cp == '#' ) /* */ { cp++; /* */ type |= NodeCountMask; /* */ } /* */ if ( !is_alpha(*cp) ) /* */ { ErrPrintF("*** BibTool: Missing format type before: %s",cp);/* */ return cp; /* */ } /* */ if ( strchr(percent_chars,*cp) == (char*)0 ) /* */ { ErrPrintF("*** BibTool: Illegal format character: %c",*cp);/* */ return cp; /* */ } /* */ type |= *(cp++); /* */ Expect(cp,'(',cp); /* */ SkipSpaces(cp); /* */ sp = cp; /* */ SkipAllowed(cp); /* */ c = *cp; /* */ *cp = '\0'; /* */ field = symbol(sp); /* */ *cp = c; /* */ SkipSpaces(cp); /* */ if ( *cp == ')' ) { cp++; } /* */ else /* */ { ErrPrintF("*** BibTool: Missing ')' in format before: %s\n",cp);/* */ return cp; /* */ } /* */ /* */ if ( (field=get_field(db,rec,field)) != NULL ) /* */ { /* */ DebugPrint1("Field found"); /* */ /* */ #define PostOr(X) (post > 0 ? post : (X)) #define PreOr(X) (pre >= 0 ? pre : (X)) #define HasMinus (type&NodeMinusMask) #define HasPlus (type&NodePlusMask) switch ( type & 0x1ff ) /* */ { /* */ case 'p': /* */ fmt_names(sb, /* */ field, /* */ PreOr(2), /* */ PostOr(0), /* */ trans); /* */ break; /* */ case 'n': /* */ if ( formatp ) init_key(3); /* */ NameStrip(format[0]) = PostOr(-1); /* */ fmt_names(sb,field,PreOr(2),0,trans); /* */ break; /* */ case 'N': /* */ if ( formatp ) init_key(3); /* */ NameStrip(format[1]) = PostOr(-1); /* */ if (NextName(format[1])) /* */ { NamePre(NextName(format[1])) = NamePreSep;/* */ } /* */ fmt_names(sb,field,PreOr(2),1,trans); /* */ break; /* */ case 'T': /* */ fmt_title(sb, /* */ field, /* */ PreOr(1), /* */ PostOr(0), /* */ trans, /* */ TRUE, /* */ TitleTitleSep); /* */ break; /* */ case 't': /* */ fmt_title(sb, /* */ field, /* */ PreOr(1), /* */ PostOr(0), /* */ trans, /* */ FALSE, /* */ TitleTitleSep); /* */ break; /* */ case 'd': /* */ (void)fmt_digits(sb, /* */ field, /* */ HasMinus, /* */ HasPlus, /* */ pre, /* */ PostOr(1), /* */ TRUE); /* */ break; /* */ case 'D': /* */ (void)fmt_digits(sb, /* */ field, /* */ HasMinus, /* */ HasPlus, /* */ pre, /* */ PostOr(1), /* */ FALSE); /* */ break; /* */ case 's': /* */ fmt_string(sb, /* */ field, /* */ PreOr(0xffff), /* */ trans, /* */ (String)" "); /* */ break; /* */ case 'W': /* */ fmt_title(sb, /* */ field, /* */ PreOr(1), /* */ PostOr(0), /* */ trans, /* */ TRUE, /* */ sym_empty); /* */ break; /* */ case 'w': /* */ fmt_title(sb, /* */ field, /* */ PreOr(1), /* */ PostOr(0), /* */ trans, /* */ FALSE, /* */ sym_empty); /* */ break; /* */ } /* */ } /* */ else /* */ { DebugPrint1("Field not found"); /* */ } /* */ } /* */ /* */ return cp; /* */ } /*------------------------*/ #undef PostOr #undef PreOr #undef HasMinus #undef HasPlus #ifdef DEBUG /*----------------------------------------------------------------------------- ** Function: show_fmt() ** Purpose: Print a format tree onto the error stream ** Arguments: ** kn ** in ** Returns: nothing **___________________________________________________ */ static void show_fmt(kn,in) /* */ register KeyNode kn; /* */ register int in; /* */ { register int i; /* */ #define NLin(S) ErrC('\n');for(i=in;i>0;i--) ErrC(' '); (void)fputs(S,err_file) #define ErrS(S) (void)fputs(S,err_file) /* */ while ( kn != (KeyNode)0 ) /* */ { switch ( NodeType(kn) ) /* */ { case NodeSTRING: /* */ ErrPrintF(" \"%s\"",NodeSymbol(kn)); /* */ NLin(""); /* */ break; /* */ case NodeTEST: /* */ ErrPrintF(" (%s)",NodeSymbol(kn)); /* */ NLin("{ "); /* */ show_fmt(NodeThen(kn),in+2); /* */ NLin("}"); /* */ NLin("{ "); /* */ show_fmt(NodeElse(kn),in+2); /* */ NLin("}"); /* */ break; /* */ case NodeOR: /* */ ErrS("{ "); /* */ show_fmt(NodeThen(kn),in+2); /* */ ErrS("}"); /* */ NLin("#"); /* */ NLin("{ "); /* */ show_fmt(NodeElse(kn),in+2); /* */ NLin("}"); /* */ break; /* */ default: /* */ fprintf(err_file,"%%%s", /* */ (NodeType(kn)&NodePlusMask?"+": /* */ (NodeType(kn)&NodeMinusMask?"-":"")));/* */ if ( NodePre(kn)>=0 ) /* */ fprintf(err_file,"%d",NodePre(kn)); /* */ if ( NodePost(kn)>=0 ) /* */ fprintf(err_file,".%d",NodePost(kn)); /* */ fprintf(err_file,"%s%c(%s) ", /* */ (NodeType(kn)&NodeCountMask?"#":""),/* */ NodeType(kn)&0xff, /* */ NodeSymbol(kn)); /* */ } /* */ kn = NodeNext(kn); /* */ } /* */ } /*------------------------*/ #endif static String sym_user = NULL; static String sym_host = NULL; /*----------------------------------------------------------------------------- ** Function: get_field() ** Purpose: Evaluate the record |rec|. ** If name starts with |@| then check the record name. ** If name starts with |$| then return the special info. ** Else search in Record |rec| for the field name and return its ** value. |NULL| is returned to indicate failure. ** Arguments: ** rec Record to analyze. ** name Field name to search for. This has to be a symbol if a ** normal field is sought. For pseudo fields it can be an ** arbitrary string. ** Returns: The address of the value or |NULL|. **___________________________________________________ */ String get_field(db,rec,name) /* */ DB db; /* */ register Record rec; /* */ register String name; /* */ { /* */ DebugPrint2("get_field ",name); /* */ #ifdef HAVE_TIME_H static struct tm *tp; /* */ static time_t the_time = 0; /* */ static char buffer[32]; /* */ /* */ if ( the_time == 0 ) /* */ { the_time = time(NULL); /* */ tp = localtime(&the_time); /* */ } /* */ #define ReturnTime(F) if ( the_time > 0 ) \ { (void)strftime(buffer,32,F,tp); \ return symbol((String)buffer); } \ return sym_empty #else #define ReturnTime(F) return sym_empty #endif /* */ if ( *name == '@' ) /* */ { if ( case_cmp(name + 1, /* */ EntryName(RecordType(rec))) ) /* */ return EntryName(RecordType(rec)); /* */ } /* */ else if ( *name == '$' ) /* */ { ++name; /* */ switch (*name) /* */ { case 'k': case 'K': /* */ if ( case_cmp(name,(String)"key") ) /* */ { return (**RecordHeap(rec) /* */ ? *RecordHeap(rec) /* */ : StringNULL); /* */ } /* */ break; /* */ case 'd': case 'D': /* */ if ( case_cmp(name,(String)"default.key") )/* */ { return DefaultKey; } /* */ else if ( case_cmp(name,(String)"day") ) /* */ { ReturnTime("%d"); } /* */ break; /* */ case 'f': case 'F': /* */ if ( case_cmp(name,(String)"fmt.et.al") ) /* */ { return EtAl; } /* */ else if ( case_cmp(name,(String)"fmt.name.pre") ) /* */ { return NamePreSep; } /* */ else if ( case_cmp(name,(String)"fmt.inter.name") )/* */ { return InterNameSep; } /* */ else if ( case_cmp(name,(String)"fmt.name.name") )/* */ { return NameNameSep; } /* */ else if ( case_cmp(name,(String)"fmt.name.title") )/* */ { return NameTitleSep; } /* */ else if ( case_cmp(name,(String)"fmt.title.title") )/* */ { return TitleTitleSep; } /* */ case 'h': case 'H': /* */ if ( case_cmp(name,(String)"hostname") ) /* */ { if ( sym_host==NULL ) /* */ { sym_host = (String)getenv("HOSTNAME"); /* */ sym_host = symbol(sym_host?sym_host:sym_empty);/* */ } /* */ return sym_host; /* */ } /* */ else if ( case_cmp(name,(String)"hour") ) /* */ { ReturnTime("%H"); } /* */ break; /* */ case 'm': case 'M': /* */ if ( case_cmp(name,(String)"month") ) /* */ { ReturnTime("%m"); } /* */ else if ( case_cmp(name,(String)"minute") )/* */ { ReturnTime("%M"); } /* */ else if ( case_cmp(name,(String)"mon") ) /* */ { ReturnTime("%B"); } /* */ break; /* */ case 's': case 'S': /* */ if ( case_cmp(name,(String)"sortkey") ) /* */ { return RecordSortkey(rec); } /* */ else if ( case_cmp(name,(String)"source") )/* */ { return RecordSource(rec); } /* */ else if ( case_cmp(name,(String)"second") )/* */ { ReturnTime("%S"); } /* */ break; /* */ case 't': case 'T': /* */ if ( case_cmp(name,(String)"type") ) /* */ { return EntryName(RecordType(rec)); } /* */ else if ( case_cmp(name,(String)"time") ) /* */ { ReturnTime("%H:%M:%S"); } /* */ break; /* */ case 'u': case 'U': /* */ if ( case_cmp(name,(String)"user") ) /* */ { if ( sym_user==NULL ) /* */ { sym_user = (String)getenv("USER"); /* */ sym_user = symbol(sym_user?sym_user:sym_empty);/* */ } /* */ return sym_user; /* */ } /* */ break; /* */ case 'w': case 'W': /* */ if ( case_cmp(name,(String)"weekday") ) /* */ { ReturnTime("%a"); } /* */ break; /* */ case 'y': case 'Y': /* */ if ( case_cmp(name,(String)"year") ) /* */ { ReturnTime("%Y"); } /* */ break; /* */ } /* */ } /* */ else /* */ { register String *cpp; /* */ String xref; /* */ register int n, count; /* */ /* */ for ( count=rsc_xref_limit;count>=0;count-- ) /* Prevent infinite loop */ { /* */ xref = NULL; /* */ for ( cpp=RecordHeap(rec), n=RecordFree(rec);/* */ n > 0; /* */ n -= 2 ) /* */ { /* */ if ( *cpp == name && *(cpp+1) != NULL ) /* */ { /* */ return ( rsc_key_expand_macros /* */ ? expand_rhs(*(cpp+1), /* */ (String)"{", /* */ (String)"}", /* */ db) /* */ : *(cpp+1) ); /* */ } /* */ /* */ if ( *cpp == sym_crossref ) { xref = *++cpp; }/* */ else cpp++; /* */ cpp++; /* */ } /* */ /* */ if ( xref == NULL ) { return StringNULL; } /* No crossref field found*/ xref = symbol(lower(expand_rhs(xref,sym_empty,sym_empty,db)));/* */ if ( (rec = db_search(db,xref)) == RecordNULL )/* */ { ErrPrintF("*** BibTool: Crossref `%s' not found.\n",xref);/* */ return StringNULL; /* */ } /* */ DebugPrint2("Following crossref to ",xref); /* */ } /* */ } /* */ /* */ return StringNULL; /* Nothing found. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: set_field() ** Purpose: Store the given field or pseudo-field in a record. ** If the field is present then the old value is ** overwritten. Otherwise a new field is added. Fields ** starting with a |$| or |@| are treated special. They ** denote pseudo fields. If such a pseudo field is ** undefined then the assignment simply fails. ** ** In contrast to the function |push_to_record()| this ** function does not assume that the arguments are ** symbols. In addition to |push_to_record()| it also ** handles pseudo-fields. ** Arguments: ** rec Record to receive the value. ** name Field name to add. ** Returns: |0| if the asignment has succeeded. **___________________________________________________ */ int set_field(db,rec,name,value) /* */ DB db; /* */ register Record rec; /* */ String name; /* */ String value; /* */ { /* */ POSSIBLY_UNUSED(db); /* */ /* */ value = symbol(value); /* */ /* */ if ( *name == '@' ) /* */ { /* */ } /* */ else if ( *name == '$' ) /* */ { ++name; /* */ switch ( *name ) /* */ { case 'k': case 'K': /* */ if ( case_cmp(name,(String)"key") ) /* */ { *RecordHeap(rec) = value; /* */ return 0; /* */ } /* */ break; /* */ case 'd': case 'D': /* */ if ( case_cmp(name,(String)"default.key") )/* */ { DefaultKey = value; /* */ return 0; /* */ } /* */ break; /* */ case 'f': case 'F': /* */ if ( case_cmp(name,(String)"fmt.et.al") ) /* */ { EtAl = value; return 0; } /* */ else if ( case_cmp(name,(String)"fmt.name.pre") )/* */ { NamePreSep = value; return 0; } /* */ else if ( case_cmp(name,(String)"fmt.inter.name") )/* */ { InterNameSep = value; return 0; } /* */ else if ( case_cmp(name,(String)"fmt.name.name") )/* */ { NameNameSep = value; return 0; } /* */ else if ( case_cmp(name,(String)"fmt.name.title") )/* */ { NameTitleSep = value; return 0; } /* */ else if ( case_cmp(name,(String)"fmt.title.title") )/* */ { TitleTitleSep = value; return 0; } /* */ case 's': case 'S': /* */ if ( case_cmp(name,(String)"sortkey") ) /* */ { RecordSortkey(rec) = value; return 0; } /* */ else if ( case_cmp(name,(String)"source") )/* */ { RecordSource(rec) = value; return 0; } /* */ break; /* */ case 't': case 'T': /* */ if ( case_cmp(name,(String)"type") ) /* */ { int type; /* */ if ( IsNormalRecord(RecordType(rec)) && /* */ (type=find_entry_type(value)) >= 0 )/* */ { RecordType(rec) = type; return 0; } /* */ } /* */ break; /* */ case 'u': case 'U': /* */ if ( case_cmp(name,(String)"user") ) /* */ { sym_user = value; return 0; } /* */ break; /* */ } /* */ } /* */ else /* */ { /* */ push_to_record(rec, symbol(name), value); /* */ return 0; /* */ } /* */ /* */ return 1; /* Nothing found. */ } /*------------------------*/ BibTool/macros.c0000644000175100017510000005241212646457472012505 0ustar genegene/*** macros.c ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #include #include #include #include "config.h" /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ static Macro macros = MacroNULL; /* */ /*----------------------------------------------------------------------------- ** Function: new_macro() ** Purpose: Allocate a new macro structure and fill it with initial values. ** Upon failure an error is raised and |exit()| is called. ** Arguments: ** name Name of the macro. This must be a symbol. ** value The value of the macro. This must be a symbol. ** next The next pointer of the |Macro| structure. ** count The initial reference count. ** Returns: The new |Macro|. **___________________________________________________ */ Macro new_macro(name, value, next, count) /* */ String name; /* */ String value; /* */ int count; /* */ Macro next; /* */ { register Macro macro; /* */ /* */ if ( (macro=(Macro)malloc(sizeof(SMacro))) == MacroNULL )/* */ { OUT_OF_MEMORY("Macro"); } /* */ /* */ MacroName(macro) = name; /* */ MacroValue(macro) = value ; /* */ MacroCount(macro) = count; /* */ NextMacro(macro) = next; /* */ return(macro); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_macro() ** Purpose: Free a list of macros. The memory allocated for the ** |Macro| given as argument and all structures ** reachable via the |NextMacro| pointer are released. ** Arguments: ** mac First Macro to release. ** Returns: nothing **___________________________________________________ */ void free_macro(mac) /* */ Macro mac; /* */ { Macro next; /* */ /* */ while (mac) /* */ { next = NextMacro(mac); /* */ ReleaseSymbol(MacroName(mac)); /* */ ReleaseSymbol(MacroValue(mac)); /* */ free(mac); /* */ mac = next; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: def_macro() ** Purpose: Define or undefine a macro. ** Arguments: ** name name of the macro. ** val NULL or the value of the new macro ** count initial count for the macro. ** Returns: nothing **___________________________________________________ */ int def_macro(name, val, count) /* */ String name; /* */ String val; /* */ int count; /* */ { register Macro *mp; /* */ /* */ name = symbol(name); /* */ if (val) val = symbol(val); /* */ /* */ for (mp = ¯os; /* */ *mp != MacroNULL; /* */ mp = &NextMacro(*mp)) /* */ { if (MacroName(*mp) == name) /* */ { if (val) /* */ { MacroValue(*mp) = val; } /* */ else /* */ { Macro mac = *mp; /* */ *mp = NextMacro(*mp); /* */ free(mac); /* */ } /* */ return 1; /* */ } /* */ } /* */ /* */ if (val) /* */ { macros = new_macro(name, val, macros, count); }/* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: look_macro() ** Purpose: Return the value of a macro if it is defined. This ** value is a symbol. ** If the macro is undefined then |NULL| is returned. In ** this case the value of |add| determines whether or not ** the macro should be defined. If it is less than 0 ** then no new macros is defined. Otherwise a new macro ** is defined. The value is the empty string and the ** initial reference count is |add|. ** Arguments: ** name The name of the macros to find. This needs not to be a symbol. ** add Initial reference count or indicator that no new macro ** is required. ** Returns: The value or |NULL|. **___________________________________________________ */ String look_macro(name, add) /* */ String name; /* */ int add; /* */ { register Macro *mp; /* */ /* */ name = symbol(name); /* */ /* */ for (mp = ¯os; /* */ *mp != MacroNULL; /* */ mp = &NextMacro(*mp)) /* */ { if (MacroName(*mp) == name) /* */ { if (MacroCount(*mp) >= 0) /* */ MacroCount(*mp) += add; /* */ return(MacroValue(*mp)); /* */ } /* */ } /* */ if (add >= 0) /* */ { def_macro(name,sym_empty,add); /* */ WARNING3("Macro '",name,"' is undefined."); /* */ } /* */ return NULL; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: foreach_macro() ** Purpose: Apply a function to each macro in turn. The function ** is called with the name and the value of the macro. If ** it returns |FALSE| then the processing of further ** macros is suppressed. ** ** The function given as argument is called with two ** string arguments. The first is the name of the macro ** and the second is its value. Both are symbols and must ** not be modified in any way. ** ** The order of the enumeration of the macros is ** determined by the implementation. No specific ** assumptions should be made about this order. ** Arguments: ** fct Function to apply to each macro. ** Returns: nothing **___________________________________________________ */ void foreach_macro(fct) /* */ int (*fct) _ARG((String ,String )); /* */ { Macro mac; /* */ for (mac = macros; /* */ mac != MacroNULL; /* */ mac = NextMacro(mac)) /* */ { if (MacroValue(mac) && /* */ ! (*fct)(MacroName(mac), MacroValue(mac))) /* */ return; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: dump_mac() ** Purpose: Write macros to a file. ** Arguments: ** fname File name of the target file. ** allp if == 0 only the used macros are written. ** Returns: nothing **___________________________________________________ */ void dump_mac(fname,allp) /* */ char *fname; /* */ int allp; /* */ { FILE *file; /* */ register Macro mac; /* */ /* */ if ( *fname == '-' && *(fname+1) == '\0' ) /* */ { file = stdout; } /* */ else if ( (file=fopen(fname,"w")) == NULL ) /* */ { ERROR2("File could not be opened: ", fname); /* */ return; /* */ } /* */ /* */ for (mac = macros; /* */ mac != MacroNULL; /* */ mac = NextMacro(mac)) /* */ { if (MacroCount(mac) > 0 || /* */ (MacroCount(mac) >= 0 && allp)) /* */ { if (MacroName(mac) == MacroValue(mac)) /* */ { (void)fprintf(file, /* */ "_string{ %s = %s } used: %d\n",/* */ MacroName(mac), /* */ MacroValue(mac), /* */ MacroCount(mac)); /* */ } /* */ else /* */ { (void)fprintf(file, /* */ "@STRING{ %s = %s } used: %d\n",/* */ MacroName(mac), /* */ MacroValue(mac), /* */ MacroCount(mac)); /* */ } /* */ } /* */ } /* */ /* */ if ( file != stdout ) (void)fclose(file); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: init_macros() ** Purpose: Initialize some macros from a table defined in the ** configuration file or given as define to the C ** compiler. This function has to be called to initialize ** the global macros. ** ** Note that this function is for internal purposes ** only. The normal user should call |init_bibtool()| ** instead. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void init_macros() /* */ { /* */ #ifdef INITIALIZE_MACROS register String name; /* */ register char**wp; /* */ static char *word_list[] = /* */ { INITIALIZE_MACROS, NULL }; /* */ /* */ for (wp = word_list; *wp != NULL; ++wp) /* */ { name = symbol((String)*wp); /* */ def_macro(name, name, -1); /* */ } /* */ #endif } /*------------------------*/ /*****************************************************************************/ /*** ***/ /*****************************************************************************/ static Macro items = MacroNULL; /*----------------------------------------------------------------------------- ** Function: def_item() ** Purpose: Define a macro. The arguments are interned as symbols. ** Arguments: ** name the name of the item ** value the value of the item ** Returns: nothing **___________________________________________________ */ static void def_item(name, value) /* */ register String name; /* */ register String value; /* */ { /* */ name = symbol(name); /* */ value = symbol(value); /* */ items = new_macro(name, value, items, 0); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: def_field_type() ** Purpose: This function adds a printing representation for a ** field name to the used list. The argument is an ** equation of the following form ** ** \textit{type = value} ** ** \textit{type} is translated to lower case and compared ** against the internal representation. \textit{value} is ** printed at the appropriate places instead. ** Arguments: ** s String containing an equation. ** Returns: nothing **___________________________________________________ */ void def_field_type(s) /* */ String s; /* */ { String name, val; /* */ Uchar c; /* */ /* */ while (*s && !is_allowed(*s)) ++s; /* */ if ( *s == '\0' ) return; /* */ name = s; /* */ while (is_allowed(*s)) ++s; /* */ c = *s; /* */ *s = '\0'; /* */ val = new_Ustring(name); /* */ *s = c; /* */ /* */ { String cp; /* */ for (cp = val; *cp; ++cp) *cp = ToLower(*cp); /* */ } /* */ /* */ name = symbol(val); /* */ free((char*)val); /* */ /* */ while (*s && !is_allowed(*s)) ++s; /* */ if ( *s == '\0' ) return; /* */ val = s; /* */ while (is_allowed(*s)) ++s; /* */ c = *s; *s = '\0'; val = symbol(val); *s = c; /* */ /* */ def_item(name, val); /* */ } /*------------------------*/ /*****************************************************************************/ /*** ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: get_mapped_or_cased() ** Purpose: ** ** ** Arguments: ** name ** mac ** type ** Returns: **___________________________________________________ */ static String get_mapped_or_cased(name, mac, type)/* */ String name; /* */ int type; /* */ register Macro mac; /* */ { static StringBuffer* sb = (StringBuffer*)NULL; /* */ /* */ for ( ; mac != MacroNULL; mac = NextMacro(mac) ) /* */ { if ( name == MacroName(mac) ) /* */ return MacroValue(mac); /* */ } /* */ /* */ if (sb == NULL && (sb=sbopen()) == NULL) /* */ { OUT_OF_MEMORY("get_item()"); } /* */ sbrewind(sb); /* */ if (type == SYMBOL_TYPE_LOWER) /* */ { sbputs((char*)name, sb); /* */ } /* */ else /* */ { switch ( type ) /* */ { case SYMBOL_TYPE_CASED: /* */ while (*name) /* */ { if (is_alpha(*name)) /* */ { (void)sbputc(ToUpper(*name), sb); /* */ for (++name; is_alpha(*name); ++name) /* */ { (void)sbputc(*name, sb); } /* */ } /* */ else /* */ { (void)sbputc(*name, sb); /* */ ++name; /* */ } /* */ } /* */ break; /* */ case SYMBOL_TYPE_UPPER: /* */ for ( ; *name; ++name ) /* */ { (void)sbputc(ToUpper(*name), sb); } /* */ break; /* */ } /* */ } /* */ return (String)sbflush(sb); /* */ } /*------------------------*/ /*****************************************************************************/ /*** ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: get_item() ** Purpose: Return the print representation of a \BibTeX{} string. ** The appearance is determined by the |items| mapping. ** If no appropriate entry is found then |type| is used to ** decide whether the item should be returned as ** upper-case, lower-case or first upper only. ** Arguments: ** name Symbol to get the print representation for. ** type One of the values |SYMBOL_TYPE_UPPER|, |SYMBOL_TYPE_LOWER|, or ** |SYMBOL_TYPE_CASED| as they are defined in |type.h|. ** Returns: A pointer to a static string. This location is reused ** upon the next invocation of this function. **___________________________________________________ */ String get_item(name, type) /* */ String name; /* */ int type; /* */ { return get_mapped_or_cased(name, items, type); /* */ } /*------------------------*/ /*****************************************************************************/ /*** ***/ /*****************************************************************************/ static Macro keys = MacroNULL; /* */ /*----------------------------------------------------------------------------- ** Function: save_key() ** Purpose: ** ** Arguments: ** name the name of the key ** key the key ** Returns: nothing **___________________________________________________ */ void save_key(name, key) /* */ String name; /* */ String key; /* */ { /* */ keys = new_macro(name, key, keys, 1); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: get_key_name() ** Purpose: ** ** Arguments: ** name the name of the key to find ** Returns: **___________________________________________________ */ String get_key_name(name) /* */ String name; /* */ { return get_mapped_or_cased(name, /* */ keys, /* */ SYMBOL_TYPE_LOWER); /* */ } /*------------------------*/ BibTool/names.c0000644000175100017510000012146712646457524012331 0ustar genegene/*** names.c ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif NameNode name_format _ARG((String s)); /* names.c */ String pp_list_of_names _ARG((String *wa,NameNode format,String trans,int max,String comma,String and,char *namesep,char *etal));/* names.c*/ #ifdef STANDALONE char * pp_names _ARG((char *s,NameNode format,String trans,int max,char *namesep,char *etal));/* names.c*/ #endif static NameNode new_name_node _ARG((int type,int strip,int trim,String pre,String mid,String post));/* names.c*/ static int is_jr _ARG((String s, int eager)); /* names.c */ static int is_lower_word _ARG((String s)); /* names.c */ static void initial _ARG((String s,String trans,int len,StringBuffer *sb));/* names.c*/ static void pp_one_name _ARG((StringBuffer *sb,String *w,NameNode format,String trans,int len,String comma,int commas));/* names.c*/ #ifdef BIBTEX_SYNTAX static void set_type _ARG((char **sp,char **midp));/* names.c */ void set_name_format _ARG((NameNode *nodep,char *s));/* names.c */ #endif /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: new_name_node() ** Purpose: Allocate a name node structure and fill it with the values ** given as arguments. ** If no more memory is available then en error is raised and ** the program is terminated. ** Arguments: ** type ** strip ** trim ** pre ** mid ** post ** Returns: The new instance of a node. **___________________________________________________ */ static NameNode new_name_node(type, strip, trim, pre, mid, post)/* */ int type; /* */ int strip; /* */ int trim; /* */ String pre; /* */ String mid; /* */ String post; /* */ { NameNode node; /* */ /* */ if ( (node = (NameNode)malloc(sizeof(SNameNode))) == NameNULL )/* */ { OUT_OF_MEMORY("NameNode"); } /* */ NameType(node) = type; /* */ NameStrip(node) = strip; /* */ NameTrim(node) = trim; /* */ NamePre(node) = pre; /* */ NameMid(node) = mid; /* */ NamePost(node) = post; /* */ NextName(node) = NameNULL; /* */ return node; /* */ } /*------------------------*/ #ifdef UNUSED /*----------------------------------------------------------------------------- ** Function: free_name_node() ** Purpose: Release the memory allocated for a node together with all ** nodes reachable via a |NextName| chain. ** It is not save to access a freed node. ** Arguments: ** node Node to free. ** Returns: nothing **___________________________________________________ */ static void free_name_node(node) /* */ NameNode node; /* */ { NameNode next; /* */ /* */ while ( node ) /* */ { next = NextName(node); /* */ free(node); /* */ node = next; /* */ } /* */ } /*------------------------*/ #endif #ifdef DEBUG /*----------------------------------------------------------------------------- ** Function: dump_name_node() ** Purpose: ** ** ** Arguments: ** n ** Returns: nothing **___________________________________________________ */ static void dump_name_node(n) /* */ NameNode n; /* */ { /* */ fputc('%',err_file); /* */ switch ( NameType(n) & NameTranslationMask ) /* */ { case NameLower: fputc('-',err_file); break; /* */ case NameUpper: fputc('+',err_file); break; /* */ case NameExternal: fputc('*',err_file); break; /* */ } /* */ if ( NameStrip(n) >= 0 ) /* */ { fprintf(err_file,"%d",NameStrip(n)); } /* */ if ( NameTrim(n) >= 0 ) /* */ { fprintf(err_file,".%d",NameTrim(n)); } /* */ switch ( NameType(n) & NameTypeMask) /* */ { case NameFirst: fputc('f',err_file); break; /* */ case NameLast: fputc('l',err_file); break; /* */ case NameVon: fputc('v',err_file); break; /* */ case NameJr: fputc('j',err_file); break; /* */ case NameString: fputc('s',err_file); break; /* */ default: fputc('?',err_file); break; /* */ } /* */ fprintf(err_file, /* */ "[%s][%s][%s]\n", /* */ (NamePre(n)?(char*)NamePre(n):""), /* */ (NameMid(n)?(char*)NameMid(n):""), /* */ (NamePost(n)?(char*)NamePost(n):"")); /* */ } /*------------------------*/ #else #define dump_name_node(N) #endif #ifdef BIBTEX_SYNTAX /*----------------------------------------------------------------------------- ** Function: set_type() ** Purpose: ** ** ** Arguments: ** sp ** midp ** Returns: **___________________________________________________ */ static void set_type(sp,midp) /* */ char **sp; /* */ char **midp; /* */ { char c, *s, *mid; /* */ int type = 0; /* */ /* */ s = *sp; /* */ if ( *(s+1) == '{' ) /* */ { mid = ++s; /* */ while ( *s && *s != '}' ) s++; /* */ c = *s; *s = '\0'; /* */ *midp = symbol(++mid); /* */ *s = c; /* */ } /* */ *sp = s; /* */ } /*------------------------*/ #define SetType(T,C) type = T; \ c = *s; *s = '\0'; pre = symbol(pre); *s = c; \ if ( *(s+1) == C ) { strip = -1; s++; } \ set_type(&s,&mid); \ post = s+1 /*----------------------------------------------------------------------------- ** Function: set_name_format() ** Purpose: ** ** ** Arguments: ** nodep ** s ** Returns: nothing **___________________________________________________ */ void set_name_format(nodep,s) /* */ NameNode *nodep; /* */ char *s; /* */ { int n, /* */ type, /* */ strip, /* */ trim = 0; /* */ String mid, /* */ pre, /* */ post; /* */ Uchar c; /* */ String space; /* */ char buffer[256]; /* */ #define UseBuffer(S) strcpy(buffer,S); s = buffer /* */ space = symbol(" "); /* */ free_name_node(*nodep); /* */ *nodep = NameNULL; /* */ /* */ if (strcmp(s,"short")==0) { UseBuffer("{ll{-}}"); }/* */ else if (strcmp(s,"med") ==0) { UseBuffer("{f{}}{ll{-}}"); }/* */ /* */ while ( *s ) /* */ { /* */ if (*s && *s != '{') /* */ { mid = s; /* */ while ( *s && *s != '{' ) s++; /* */ c = *s; /* */ *s = '\0'; /* */ mid = symbol(mid); /* */ *s = c; /* */ *nodep = new_name_node(NameString, /* */ -1, /* */ -1, /* */ StringNULL, /* */ mid, /* */ StringNULL); /* */ nodep = &NextName(*nodep); /* */ /* */ if ( c == '\0' ) return; /* */ } /* */ /* */ pre = ++s; /* */ type = NoName; /* */ mid = space; /* */ strip = 1; /* */ for ( n = 1 ; n > 0; ++s ) /* */ { switch (*s) /* */ { case '{': n++; break; /* */ case '}': n--; break; /* */ case 'f': SetType(NameFirst,'f'); break; /* */ case 'l': SetType(NameLast,'l'); break; /* */ case 'v': SetType(NameVon,'v'); break; /* */ case 'j': SetType(NameJr,'j'); break; /* */ case '\0': return; /* */ } /* */ } /* */ /* */ if ( type != NoName ) /* */ { c = *(s-1); /* */ *(s-1) = '\0'; /* */ post = symbol(post); /* */ *(s-1) = c; /* */ *nodep = new_name_node(type, strip, trim, pre, mid, post);/* */ dump_name_node(*nodep); /* */ nodep = &NextName(*nodep); /* */ } /* */ } /* */ } /*------------------------*/ #endif /*----------------------------------------------------------------------------- ** Function: name_format() ** Purpose: ** ** ** Arguments: ** s ** Returns: **___________________________________________________ */ NameNode name_format(s) /* */ String s; /* */ { int type, /* */ strip, /* */ trim; /* */ String pre, /* */ mid, /* */ post; /* */ Uchar c; /* */ String cp; /* */ NameNode node = NameNULL; /* */ NameNode *nnp; /* */ static char *msg = "Missing ']' in format string.";/* */ #define OptionalArg(S) \ if ( *cp == '[' ) \ { for ( S=++cp; *cp && *cp != ']'; cp++) ; \ if ( *cp ) \ { c = *cp; *cp = '\0'; S = symbol(S); *(cp++) = c; } \ else { S = sym_empty; WARNING(msg); } \ } else { S = sym_empty; } /* */ nnp = &node; /* */ cp = s; /* */ while (*cp) /* */ { /* */ if ( *cp == '%' ) /* */ { /* */ switch ( *++cp ) /* */ { case '+': type = NameUpper; cp++; break;/* */ case '-': type = NameLower; cp++; break;/* */ case '*': type = NameExternal; cp++; break;/* */ default: type = NameNone; /* */ } /* */ if ( is_digit(*cp) ) /* */ { strip = 0; /* */ while(is_digit(*cp)) /* */ { strip = strip*10 + (*cp++) - '0';} /* */ } else { strip = -1; } /* */ /* */ if ( *cp == '.' ) /* */ { trim = 0; /* */ cp++; /* */ while(is_digit(*cp)) /* */ { trim = trim*10 + (*cp++) - '0';} /* */ } else { trim = -1; } /* */ /* */ switch ( *cp ) /* */ { case 'f': type |= NameFirst; break; /* */ case 'l': type |= NameLast; break; /* */ case 'v': type |= NameVon; break; /* */ case 'j': type |= NameJr; break; /* */ default: type |= NoName; /* */ error(ERR_ERROR|ERR_POINT, /* */ (String)"Wrong type of format.", /* */ StringNULL, /* */ StringNULL, /* */ s, /* */ cp, 0, (char*)0); /* */ } /* */ cp++; /* */ OptionalArg(pre); /* */ OptionalArg(mid); /* */ OptionalArg(post); /* */ } /* */ else /* */ { mid = cp; /* */ while ( *cp && *cp != '%' ) { cp++; } /* */ c = *cp; /* */ *cp = '\0'; /* */ mid = symbol(mid); /* */ *cp = c; /* */ type = NameString; /* */ pre = NULL; /* */ post = NULL; /* */ strip = -1; /* */ trim = -1; /* */ } /* */ if ( type != NoName ) /* */ { *nnp = new_name_node(type, /* */ strip, /* */ trim, /* */ pre, /* */ mid, /* */ post); /* */ nnp = &NextName(*nnp); /* */ } /* */ } /* */ return node; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: pp_list_of_names() ** Purpose: ** ** ** Arguments: ** wa Word array of name constituents ** format ** trans ** max ** comma "," ** and name separator ** namesep ** etal ** Returns: Pointer to static string which is reused upon the next ** invocation of this function. **___________________________________________________ */ String pp_list_of_names(wa,format,trans,max,comma,and,namesep,etal)/* */ String *wa; /* */ NameNode format; /* */ String trans; /* */ int max; /* */ String comma; /* */ String and; /* */ char *namesep; /* */ char *etal; /* */ { String *w; /* */ String word; /* */ int commas; /* */ int first = TRUE; /* */ static StringBuffer *sb = (StringBuffer*)0; /* */ /* */ if ( sb == (StringBuffer*)0 /* */ && (sb=sbopen()) == (StringBuffer*)0 ) /* */ { OUT_OF_MEMORY("name list"); } /* */ else /* */ { sbrewind(sb); } /* */ /* */ while ( *wa ) /* */ { /* */ if ( *(wa+1) == NULL /* Look at the end */ && strcmp((char*)(*wa),"others")==0 ) /* for `and others' */ { sbputs(etal,sb); /* */ break; /* */ } /* */ if ( max >= 0 && --max < 0 ) /* */ { sbputs(etal,sb); /* */ break; /* */ } /* */ /* */ commas = 0; /* */ for( w = wa; *w && *w != and; w++ ) /* */ { if ( *w == comma ) commas++; /* */ DebugPrint1(*w); /* */ } /* */ word = *w; /* */ *w = NULL; /* */ if ( first ) { first = FALSE; } /* */ else { sbputs(namesep,sb); } /* */ pp_one_name(sb,wa,format,trans,(int)(w-wa),comma,commas);/* */ *w = word; /* */ wa = ( word != NULL? ++w : w ) ; /* */ } /* */ /* */ return (String)sbflush(sb); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: pp_one_name() ** Purpose: ** ** ** Arguments: ** sb ** w ** len ** comma ** commas ** Returns: nothing **___________________________________________________ */ static void pp_one_name(sb, w, format, trans, len, comma, commas)/* */ StringBuffer *sb; /* */ String *w; /* */ NameNode format; /* */ String trans; /* */ int len; /* */ String comma; /* */ int commas; /* */ { NameNode nn; /* */ char t; /* */ char *type; /* */ String tr; /* */ int i, j, again; /* */ int first, last, von, jr; /* */ /* */ first = last = von = jr = 0; /* */ if ( len < 1 ) return; /* */ /* */ if ( (type=(char*)malloc(len)) == NULL ) /* */ { OUT_OF_MEMORY("name type"); } /* */ /* */ #ifdef DEBUG ErrPrint("+++ BibTool: Name parts: "); /* */ for (i = 0; i < len; i++) /* */ { ErrPrintF("\n\t/%s/ ",w[i]); } /* */ ErrC('\n'); /* */ #endif /* */ if ( commas == 0 ) /*------------------------*/ { /* ff vv ll */ j = len - 1; /* ff vv ll jr */ if ( is_jr((String)w[j], TRUE) ) /* */ { type[j--] = 'j'; jr++; } /* */ if ( j >= 0 ) /* */ { type[j] = 'l'; last++; } /* */ i = 0; /* */ while ( i < j && !is_lower_word((String)w[i]) )/* */ { type[i++] = 'f'; first++; } /* */ while ( i < j && is_lower_word((String)w[i]) ) /* */ { type[i++] = 'v'; von++; } /* */ while ( i < j ) /* */ { type[i++] = 'l'; last++; } /* */ } /* */ else if ( commas == 1 /*------------------------*/ && len > 2 /* ff vv ll, jj */ && w[len-2] == comma /* */ && is_jr(w[len-1], FALSE) ) /* */ { j = len - 1; /* */ type[j--] = 'j'; jr++; /* */ type[j--] = ','; /* */ if ( j >= 0 ) { type[j--] = 'l'; last++; } /* */ i = 0; /* */ while ( i < j && !is_lower_word((String)w[i]) )/* */ { type[i++] = 'f'; first++; } /* */ while ( i < j && is_lower_word((String)w[i]) ) /* */ { type[i++] = 'v'; von++; } /* */ while ( i < j ) /* */ { type[i++] = 'l'; last++; } /* */ } /* */ else /* */ { i = 0; /*------------------------*/ if ( is_lower_word((String)w[i]) ) /* vv ll, ff */ { while ( i < len && /* */ w[i] != comma && /* */ is_lower_word((String)w[i]) ) /* */ { type[i++] = 'v'; von++; } /* */ } /* */ /*------------------------*/ while ( i < len && w[i] != comma ) /* ll, ff vv */ { type[i++] = 'l'; last++; } /* */ if (i < len) { type[i++] = ','; } /* */ /*------------------------*/ if ( commas == 2 ) /* ll, jj, ff vv */ { while ( i < len && w[i] != comma ) /* */ { type[i++] = 'j'; jr++; } /* */ if (i < len) { type[i++] = ','; } /* */ } /* */ while ( i < len && !is_lower_word((String)w[i]) )/* */ { if (w[i] == comma) { /* */ type[i++] = ','; /* */ } else { /* */ type[i++] = 'f'; first++; /* */ } /* */ } /* */ while ( i < len && is_lower_word((String)w[i]) )/* */ { type[i++] = 'v'; von++; } /* */ } /* */ /* */ #ifdef DEBUG ErrPrint("+++ BibTool: Classified name parts: ");/* */ for ( i = 0; i < len; i++) /* */ { ErrPrintF2("\n\t%c/%s/ ",type[i], w[i]); } /* */ ErrC('\n'); /* */ #endif /* */ for ( nn = format; /* */ nn != NameNULL; /* */ nn = NextName(nn) ) /* */ { int strip = NameStrip(nn); /* */ int trim = NameTrim(nn); /* */ dump_name_node(nn); /* only in debug mode */ switch( NameType(nn) & NameTypeMask ) /* */ { case NameFirst: t = 'f'; j = first; break; /* */ case NameLast: t = 'l'; j = last; break; /* */ case NameVon: t = 'v'; j = von; break; /* */ case NameJr: t = 'j'; j = jr; break; /* */ case NameString: sbputs((char*)NameMid(nn),sb);/* */ default: t = ' '; j = 0; /* */ } /* */ switch( NameType(nn) & NameTranslationMask ) /* */ { case NameLower: tr = trans_lower; break; /* */ case NameUpper: tr = trans_upper; break; /* */ case NameNone: tr = trans_id; break; /* */ default: tr = trans; /* */ } /* */ /* */ if ( j > 0 ) /* */ { sbputs((char*)NamePre(nn), sb); /* */ again = FALSE; /* */ for ( i = 0; i < len; i++ ) /* */ { if ( type[i] == t ) /* */ { /* */ if ( trim-- == 0 ) break; /* */ if ( again ) sbputs((char*)NameMid(nn), sb);/* */ else again = TRUE; /* */ /* */ initial(w[i], tr, strip, sb); /* */ } /* */ } /* */ sbputs((char*)NamePost(nn), sb); /* */ } /* */ } /* */ /* */ free(type); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: initial() ** Purpose: ** ** ** Arguments: ** s ** sb ** Returns: nothing **___________________________________________________ */ static void initial(s,trans,len,sb) /* */ String s; /* */ String trans; /* */ int len; /* */ StringBuffer *sb; /* */ { /* */ if ( len < 0 ) { sbputs((char*)s, sb); return; } /* */ /* */ while ( len > 0 ) /* */ { if (*s=='\0') { return; } /* */ if ( is_alpha(*s) ) /* */ { sbputc(trans[*s], sb); /* */ len--; /* */ } /* */ s++; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: is_jr() ** Purpose: ** ** ** Arguments: ** s string to consider ** eager indicator whether single letters should be classified as ** Roman numbers ** Returns: **___________________________________________________ */ static int is_jr(s, eager) /* */ String s; /* */ int eager; /* */ { /* */ switch ( ToLower(*s) ) /* */ { case 'j': /* */ s++; /* */ return ( case_cmp(s,(String)"r") || /* */ case_cmp(s,(String)"r.") || /* */ case_cmp(s,(String)"unior") ); /* */ case 's': /* */ s++; /* */ return ( case_cmp(s,(String)"en") || /* */ case_cmp(s,(String)"en.") || /* */ case_cmp(s,(String)"enior") ); /* */ case 'm': /* */ s++; /* */ return ( case_cmp(s,(String)"d") ); /* */ case 'p': /* */ s++; /* */ return ( case_cmp(s,(String)"hD") || /* */ case_cmp(s,(String)"hD.") ); /* */ case 'i': /* */ s++; /* */ return ( (*s == '\0' && eager) || /* */ strcmp((char*)s,"I") == 0 || /* */ strcmp((char*)s,"II") == 0 || /* */ strcmp((char*)s,"V") == 0 || /* */ strcmp((char*)s,"X") == 0 ); /* */ case 'v': /* */ s++; /* */ return ( (*s == '\0' && eager) || /* */ strcmp((char*)s,"I") == 0 || /* */ strcmp((char*)s,"II") == 0 || /* */ strcmp((char*)s,"III") == 0 ); /* */ case 'x': /* */ s++; /* */ return ( (*s == '\0' && eager) || /* */ strcmp((char*)s,"I") == 0 || /* */ strcmp((char*)s,"II") == 0 || /* */ strcmp((char*)s,"III") == 0 || /* */ strcmp((char*)s,"IV") == 0 || /* */ strcmp((char*)s,"V") == 0 || /* */ strcmp((char*)s,"VI") == 0 || /* */ strcmp((char*)s,"VII") == 0 || /* */ strcmp((char*)s,"VIII") == 0 || /* */ strcmp((char*)s,"IX") == 0 || /* */ strcmp((char*)s,"X") == 0 || /* */ strcmp((char*)s,"XI") == 0 || /* */ strcmp((char*)s,"XII") == 0 || /* */ strcmp((char*)s,"XIII") == 0 || /* */ strcmp((char*)s,"XIV") == 0 || /* */ strcmp((char*)s,"XV") == 0 || /* */ strcmp((char*)s,"XVI") == 0 || /* */ strcmp((char*)s,"XVII") == 0 || /* */ strcmp((char*)s,"XVIII") == 0 || /* */ strcmp((char*)s,"XIX") == 0 || /* */ strcmp((char*)s,"XX") == 0 ); /* */ case 'e': /* */ return ( case_cmp(++s,(String)"sc") || /* */ case_cmp(s,(String)"sc.") ); /* */ } /* */ return FALSE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: is_lower_word() ** Purpose: Test if the word given as argument starts with a lower case ** letter. Non letter characters are ignored. ** TeX control sequences are partially ignored: ** ** Arguments: ** s Word to test ** Returns: TRUE or FALSE **___________________________________________________ */ static int is_lower_word(s) /* */ register String s; /* */ { /* */ while(*s) /* */ { if ( is_lower(*s) ) return TRUE; /* */ if ( is_upper(*s) ) return FALSE; /* */ if ( *s == '\\' ) { s++; if (*s) s++; } /* */ else s++; /* */ } /* */ return FALSE; /* */ } /*------------------------*/ /*---------------------------------------------------------------------------*/ #ifdef STANDALONE /*----------------------------------------------------------------------------- ** Function*: pp_names() ** Purpose: Take a string consisting of a list of names, parse it and ** reformat it according to a format specification. ** This function is modeled according to the specification ** for |format.name$| in \BibTeX. ** Arguments: ** s string to be parsed and reformatted. ** format the format ** trans translation table ** max ** namesep string to be inserted between names. ** etal string to be added instead of `and others' ** Returns: a new symbol with the reformatted names. **___________________________________________________ */ char * pp_names(s, format, trans, max, namesep, etal)/* */ char *s; /* */ NameNode format; /* */ String trans; /* */ int max; /* */ char *namesep; /* */ char *etal; /* */ { char *wp, /* */ *comma, /* */ *and; /* */ int brace, /* */ n, /* */ cc; /* */ char **words; /* */ /* */ if ( format == NameNULL ) return s; /* */ /* */ s = new_string(s); /* */ wp = s; /* */ brace = 0; /* */ n = 0; /* */ comma = ","; /* */ and = "&"; /* */ /* */ for ( ; *s; s++ ) /* */ { switch(*s) /* */ { case '{': brace++; break; /* */ case '}': brace--; break; /* */ case ',': /* */ if ( brace < 1 ) /* */ { *s = '\0'; /* */ if (*wp) { push_string(wp); n++; } /* */ push_string(comma); n++; /* */ wp = s+1; /* */ } /* */ break; /* */ case ' ': case '~': case '\t': case '\n': /* */ case '\r': /* */ if ( brace < 1 ) /* */ { *s = '\0'; /* */ if (*wp) /* */ { push_string(strcmp(wp,"and")==0?and:wp);/* */ n++; /* */ } /* */ wp = s+1; /* */ } /* */ break; /* */ } /* */ } /* */ if (*wp) { push_string(wp); n++; } /* */ push_string(NULL); /* */ n++; /* */ /* */ if ( (words=(char**)malloc(n*sizeof(char*))) == (char**)0 )/* Allocate */ { OUT_OF_MEMORY("Names"); } /* temp. array of words. */ /* */ while( --n >= 0 ) /* Transfer the stack into*/ { words[n] = pop_string(); /* the word array. */ } /* */ /* */ wp = symbol(pp_list_of_names(words, /* */ format, /* */ trans, /* */ max, /* */ comma, /* */ and, /* */ namesep,etal)); /* */ /* */ free(words); /* */ free(s); /* */ return wp; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function*: main() ** Purpose: Main routine ** Arguments: ** argc Number of arguments (+1) ** argv Array of command line arguments (and program name) ** Returns: **___________________________________________________ */ int main(argc,argv) /* */ int argc; /* */ char *argv[]; /* */ { Uchar s[1024]; /* */ NameNode format = NameNULL; /* */ /* */ init_type(); /* */ /* */ fputs("Format: ",stdout); /* */ gets(s); /* */ /* */ format = name_format(s); /* */ /* */ while ( gets(s) ) /* */ { puts (pp_names(s,format,trans_lower,-1," and "," and others"));/* */ } /* */ } /*------------------------*/ int rsc_quiet = 1; /* gcc -g -DDEBUG -DSTANDALONE names.c stack.o symbols.o sbuffer.o type.o error.o -o names ./names */ #endif BibTool/parse.c0000644000175100017510000012746512646457534012345 0ustar genegene/*** parse.c ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBKPATHSEA #ifdef __STDC__ #define HAVE_PROTOTYPES #endif #include #endif /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int parse_bib _ARG((Record rec)); /* parse.c */ int read_rsc _ARG((String name)); /* parse.c */ int see_bib _ARG((String fname)); /* parse.c */ static int see_rsc _ARG((String fname)); /* parse.c */ int seen _ARG((void)); /* parse.c */ static int fill_line _ARG((void)); /* parse.c */ static int parse_block _ARG((int quotep)); /* parse.c */ static int parse_equation _ARG((Record rec)); /* parse.c */ static int parse_key _ARG((int alpha)); /* parse.c */ static int parse_rhs _ARG((void)); /* parse.c */ static int parse_string _ARG((int quotep)); /* parse.c */ static int parse_symbol _ARG((int alpha)); /* parse.c */ static int parse_value _ARG((void)); /* parse.c */ static int see_bib_msg _ARG((char *s)); /* parse.c */ static int skip _ARG((int inc)); /* parse.c */ static int skip_c _ARG((void)); /* parse.c */ static int skip_nl _ARG((void)); /* parse.c */ static void init___ _ARG((char ***pathp,char **pattern,char **envvp,char *env));/* parse.c*/ static void init_parse _ARG((void)); /* parse.c */ static void parse_number _ARG((void)); /* parse.c */ void init_read _ARG((void)); /* parse.c */ void set_rsc_path _ARG((String val)); /* parse.c */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Variable*: parse_sb ** Purpose: ** ** **___________________________________________________ */ static StringBuffer * parse_sb = (StringBuffer*)NULL; #define FLBLEN 80 /* initial size and increment of line buffer */ static char *filename; static FILE *file; static String file_line_buffer; static String flp; static size_t fl_size = 0; static int flno = 0; /*---------------------------------------------------------------------------*/ #define EmptyC (*flp=='\0') #define CurrentC *flp #define FutureC *(flp+1) #define ClearLine (*flp='\0') #define GetC skip(TRUE) #define NextC *(flp++) #define SkipC ++flp #define TestC skip(FALSE) #define UnGetC flp-- #define InitLine *file_line_buffer = '\0'; \ flp = file_line_buffer; \ flno = 0; /*---------------------------------------------------------------------------*/ static String str_unexpected = (String)"Unexpected character encountered"; static char *str_stdin = ""; #define Error3(X,Y,Z) error(ERR_ERROR|ERR_POINT|ERR_FILE,(String)X, \ (String)Y,(String)Z, \ file_line_buffer,flp,flno,filename) #define Error(X) error(ERR_ERROR|ERR_POINT|ERR_FILE,(String)X, \ sym_empty,sym_empty, \ file_line_buffer,flp,flno,filename) #define Warning(X) error(ERR_WARN|ERR_POINT|ERR_FILE,(String)X, \ sym_empty,sym_empty, \ file_line_buffer,flp,flno,filename) #define UnterminatedError(X,LINE) \ error(ERR_ERROR|ERR_FILE,(String)X, \ sym_empty,sym_empty, \ NULL,NULL,LINE,filename) #define UnexpectedError Error(str_unexpected) /*----------------------------------------------------------------------------- ** Function: init___() ** Purpose: Initialize the reading apparatus. ** Arguments: ** pathp ** pattern ** envvp ** env ** Returns: nothing **___________________________________________________ */ static void init___(pathp,pattern,envvp,env) /* */ char ***pathp; /* */ char **pattern; /* */ char **envvp; /* */ char *env; /* */ { register char **cpp, /* */ *cp; /* */ /* */ if ( *pathp != (char**)0 ) /* */ { free((char*)*pathp); /* */ *pathp = (char**)0; /* */ } /* */ /* */ if ( (cp = getenv(env)) != NULL ) /* */ { *envvp = cp; } /* */ /* */ if ( *envvp ) /* */ { *pathp = px_s2p(*envvp,*rsc_env_sep); /* */ if ( *pathp == (char**)0 ) /* */ { WARNING2(env,"search path extension failed.");/* */ } /* */ DebugPrint2("Path extension ",env); /* */ } /* */ /* */ if ( *rsc_dir_file_sep != '/' ) /* */ { for ( cpp = pattern; *cpp; ++cpp ) /* */ { *cpp = new_string(*cpp); /* */ for (cp = *cpp; *cp; ++cp ) /* */ { if ( *cp == '/' ) *cp = *rsc_dir_file_sep; /* */ } /* */ } /* */ } /* */ } /*------------------------*/ #ifndef HAVE_LIBKPATHSEA static char **f_path = (char**)0; /* */ static char *f_pattern[] = /* */ { "%s/%s", "%s/%s.bib", NULL }; /* */ #endif /*----------------------------------------------------------------------------- ** Function: init_read() ** Purpose: Initialize the reading apparatus. ** Primarily try to figure out the file search path. ** ** Note that this function is for internal purposes ** mainly. The normal user should call |init_bibtool()| ** instead. Just in case the search paths are changed ** afterwards this function has to be called again to ** propagate the information. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void init_read() /* */ { /* */ #ifndef HAVE_LIBKPATHSEA init___(&f_path, /* */ f_pattern, /* */ (char**)&rsc_v_bibtex, /* */ (char*)rsc_e_bibtex ); /* */ #endif } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: see_bib_msg() ** Purpose: Message function for use with |px_fopen()|. ** Arguments: ** s String to print ** Returns: |TRUE| to indicate that continuation is desired. **___________________________________________________ */ static int see_bib_msg(s) /* */ register char *s; /* */ { /* */ if ( rsc_verbose ) VerbosePrint2("Trying ",s); /* */ return TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: see_bib() ** Purpose: Open a \BibTeX{} file to read from. ** If the argument is |NULL| then |stdin| is used as ** input stream. ** ** This function has to be called before |parse()| can be ** called. It initializes the parser routine and takes ** care that the next reading is done from the given ** file. ** ** The file opened with this function has to be closed ** with |seen()|. ** ** This function is for internal purposes mainly. See ** |read_db()| for a higher level function to read a ** database. ** Arguments: ** fname Name of the file or |NULL|. ** Returns: |TRUE| iff the file could be opened for reading. **___________________________________________________ */ int see_bib(fname) /* */ register String fname; /* */ { /* */ init_parse(); /* */ InitLine; /* */ if ( fname == NULL ) /* */ { /* */ filename = str_stdin; /* */ file = stdin; /* */ return TRUE; /* */ } /* */ #ifdef HAVE_LIBKPATHSEA filename = kpse_find_file((char*)fname, /* */ kpse_bib_format, /* */ TRUE); /* */ if ( filename == NULL ) return FALSE; /* */ file = fopen(filename,"r"); /* */ #else file = px_fopen((char*)fname, /* */ "r", /* */ f_pattern, /* */ f_path, /* */ see_bib_msg); /* */ filename = px_filename; /* */ #endif return ( file != NULL ); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: seen() ** Purpose: Close input file for the \BibTeX{} reading apparatus. ** After this function has been called |parse()| might ** not return sensible results. ** ** This function is for internal purposes mainly. See ** |read_db()| for a higher level function to read a ** database. ** Arguments: none ** Returns: |FALSE| if an attempt was made to close an already ** closed file. **___________________________________________________ */ int seen() /* */ { /* */ if ( file == stdin ) /* */ { file = NULL; /* */ return TRUE; /* */ } /* */ else if ( file ) /* */ { (void)fclose(file); /* */ file = NULL; /* */ return TRUE; /* */ } /* */ return FALSE; /* */ } /*------------------------*/ #define Expect(C,N) if ( GetC != C ) { UnexpectedError; return(N); } #define ExpectSymbol(C,N) if (!parse_symbol(C)) return(N) #define ExpectKey(C,N) if (!parse_key(C)) return(N) #define ExpectRhs(N) if (!parse_rhs()) return(N) #define ExpectEq(R,N) if (!parse_equation(R)) return(N) #define ExpectEqMac(R,N) if (!parse_equation(R)) return(N) /*----------------------------------------------------------------------------- ** Function: init_parse() ** Purpose: Initialize the parser. ** ** Arguments: none ** Returns: nothing **___________________________________________________ */ static void init_parse() /* */ { /* */ if ( fl_size != 0 ) return; /* Already initialzed? */ /* */ fl_size = FLBLEN; /* */ if ( (file_line_buffer=(String)malloc(fl_size*sizeof(Uchar))) == NULL )/* */ { OUT_OF_MEMORY("line buffer"); } /* Allocate line buffer */ /* or message and exit. */ if ( parse_sb == (StringBuffer*)0 && /* Try to initialize the */ (parse_sb=sbopen()) == (StringBuffer*)0 ) /* string buffer for the */ { OUT_OF_MEMORY("parser"); /* parser or exit */ } /* with error message. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fill_line() ** Purpose: Filling the line buffer until end-of-line or end-of-file ** encountered. ** ** Since I don't want to use a fixed line length the algorithm ** is a little bit more complicated. ** First I try to read into the file_line_buffer as it is. ** If this succeeds I check to see what caused |fgets| to ** terminate. Either a end-of-line is in the buffer or ** the buffer is not filled, i.e. end-of-file has been ** encountered, then |0| is returned. ** Otherwise the buffer has been filled and I try to enlarge the ** buffer and read another chunk of bytes. ** Arguments: none ** Returns: Returns 0 iff a character has been read. **___________________________________________________' */ static int fill_line() /* */ { register size_t len; /* */ /* */ flp = file_line_buffer; /* Reset line pointer */ ++flno; /* Increase line number */ /* */ if ( fgets((char*)file_line_buffer,fl_size,file) == NULL )/*Get first chunk*/ { ClearLine; /* or report EOF */ DebugPrint1("Reading failed for first line."); /* */ return 1; /* */ } /* */ /* */ FOREVER /* */ { for (len = 0; /* Find the end */ file_line_buffer[len] != '\0'; /* of the buffer and */ ++len ) ; /* count the length. */ /* */ #ifdef DEBUG ErrPrintF2("+++ BibTool: line buffer: used %d of %d\n",len+1,fl_size);/* */ #endif /* */ if ( file_line_buffer[len-1] == '\n' /* */ || len < fl_size - 1) /* */ { return 0; } /* */ /* */ if ( (file_line_buffer = (String) /* Try to enlarge */ realloc((char*)file_line_buffer, /* the line buffer */ fl_size+=FLBLEN)) == NULL ) /* */ { OUT_OF_MEMORY("line buffer"); } /* */ flp = file_line_buffer; /* Reset line pointer */ /* */ if ( fgets((char*)file_line_buffer+len,FLBLEN+1,file)/* */ == NULL ) /* */ { return 0; } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: skip() ** Purpose: Skip over spaces. Return the next non-space character or |EOF|. ** If inc is TRUE point to the first character after the one ** returned. ** Arguments: ** inc ** Returns: The next character **___________________________________________________ */ static int skip(inc) /* */ register int inc; /* */ { /* */ FOREVER /* */ { if ( EmptyC && fill_line() ) return EOF; /* */ else if ( is_space(CurrentC) ) SkipC; /* */ else return ( inc ? NextC : CurrentC ); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: skip_c() ** Purpose: Return the next character or EOF. ** Arguments: none ** Returns: **___________________________________________________ */ static int skip_c() /* */ { /* */ FOREVER /* */ { if ( EmptyC && fill_line() ) return EOF; /* */ else { return ( NextC ); } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: skip_nl() ** Purpose: Return the next character or EOF. ** Any number of spaces is returned as a single space. ** Doubled newlines are preserved. ** Arguments: none ** Returns: **___________________________________________________ */ static int skip_nl() /* */ { static int state = FALSE; /* */ int c; /* */ /* */ if ( state ) { state = FALSE; return '\n'; } /* */ /* */ FOREVER /* */ { if ( EmptyC && fill_line() ) return EOF; /* */ else if ( is_space(CurrentC) ) /* */ { /* */ for ( c = skip_c(); /* */ c != EOF && is_space(c) && c != '\n'; /* */ c = skip_c() ) {} /* */ if ( c == EOF ) return EOF; /* */ if ( c != '\n' ) { UnGetC; return ' '; } /* */ /* */ for ( c = skip_c(); /* */ c != EOF && is_space(c) && c != '\n'; /* */ c = skip_c() ) {} /* */ if ( c == EOF ) return EOF; /* */ if ( c != '\n' ) { UnGetC; return ' '; } /* */ /* */ for ( c = skip_c(); /* */ c != EOF && is_space(c); /* */ c = skip_c() ) {} /* */ if ( c == EOF ) return EOF; /* */ UnGetC; /* */ state = TRUE; /* */ return '\n'; /* */ } /* */ else { return ( NextC ); } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_symbol() ** Purpose: Parse a symbol and push it to the stack. ** Upon failure issue an appropriate message. ** Arguments: ** alpha indicator that the symbol has to start with an alpha character ** Returns: Success status **___________________________________________________ */ static int parse_symbol(alpha) /* */ register int alpha; /* */ { register Uchar c; /* */ register String cp; /* */ /* */ c = GetC; /* */ cp = flp-1; /* */ if ( alpha && (! is_alpha(c)) ) /* */ { Warning("Symbol does not start with a letter");/* */ } /* */ while ( is_allowed(CurrentC) ) { SkipC; } /* */ c = CurrentC; /* */ CurrentC = '\0'; /* */ push_string(symbol(lower(cp))); /* */ CurrentC = c; /* */ return TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_key() ** Purpose: Parse a symbol and push it to the stack. ** Upon failure issue an appropriate message. ** Arguments: ** alpha indicator that the symbol has to start with an alpha character ** Returns: Success status **___________________________________________________ */ static int parse_key(alpha) /* */ register int alpha; /* */ { register Uchar c; /* */ register String cp; /* */ /* */ c = GetC; /* */ cp = flp - 1; /* */ if ( alpha && (! is_alpha(c)) ) /* */ { Error("Key does not start with a letter"); /* */ return(FALSE); /* */ } /* */ while ( is_allowed(CurrentC) || CurrentC == '\'')/* */ { SkipC; } /* */ c = CurrentC; /* */ CurrentC = '\0'; /* */ if ( rsc_key_case ) /* */ { String s; /* */ s = symbol(cp); /* */ cp = symbol(lower(cp)); /* */ save_key(cp,s); /* */ } /* */ else /* */ { cp = symbol(lower(cp)); /* */ } /* */ push_string(cp); /* */ CurrentC = c; /* */ return TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_number() ** Purpose: Parse a number and push it to the stack. ** This function is called when at least one digit has been seen. ** Thus no error can occur in this function. ** Arguments: none ** Returns: nothing **___________________________________________________ */ static void parse_number() /* */ { register Uchar c; /* */ register String cp; /* */ /* */ cp = flp; /* */ while ( is_digit(CurrentC) ) { SkipC; } /* */ c = CurrentC; /* */ CurrentC = '\0'; /* */ push_string(symbol(cp)); /* */ CurrentC = c; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_string() ** Purpose: Parse a string and push it to the stack. ** A string is something enclosed in "" ** Consider the brace level to determine the end of the string. ** Arguments: ** quotep Boolean. TRUE iff the leading " has already been stripped off ** the input stream. ** Returns: Success status **___________________________________________________" */ static int parse_string(quotep) /* */ int quotep; /* */ { int c; /* */ int left; /* */ int start_flno = flno; /* */ /* */ left = 0; /* */ if ( quotep ) (void)sbputchar('"',parse_sb); /*" */ do /* */ { switch ( c=skip_nl() ) /* */ { case EOF: /* */ UnterminatedError("Unterminated double quote",/* */ start_flno); /* */ return(FALSE); /* */ case '{': left++; (void)sbputchar((char)c,parse_sb); break;/* */ case '}': if ( left--<0 ) /* */ { Warning("Expecting \" here"); } /* */ (void)sbputchar((char)c,parse_sb);/* */ break; /* */ case '\\': (void)sbputchar((char)c,parse_sb); c = NextC;/* */ (void)sbputchar((char)c,parse_sb); c = ' ';/* */ break; /* */ case '"': if ( !quotep ) break; /* */ default: (void)sbputchar((char)c,parse_sb);/* */ } /* */ } while ( c != '"' ); /* */ /* */ if ( left ) Warning("Unbalanced parenthesis"); /* */ return(TRUE); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_block() ** Purpose: Parse a block and push it to the stack. ** A block is something enclosed in {} ** Consider the brace level to determine the end of the string. ** Arguments: ** quotep Boolean. TRUE iff the leading { has already been stripped off ** the input stream. ** Returns: Success status **___________________________________________________ */ static int parse_block(quotep) /* */ int quotep; /* */ { int c; /* */ int left; /* */ int start_flno = flno; /* */ /* */ left = 1; /* */ if ( quotep ) (void)sbputchar('{',parse_sb); /* */ /* */ FOREVER /* */ { switch ( c=skip_nl() ) /* */ { case EOF: /* */ UnterminatedError("Unterminated open brace",/* */ start_flno); /* */ return FALSE; /* */ case '{': left++; break; /* */ case '}': /* */ if ( --left < 1 ) /* */ { if ( quotep ) (void)sbputchar('}',parse_sb);/* */ return TRUE; /* */ } /* */ } /* */ (void)sbputchar(c,parse_sb); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_rhs() ** Purpose: Parse the right hand side of an item. ** This can be composed of strings, blocks, numbers, and symbols ** separated by # ** Arguments: none ** Returns: Success status **___________________________________________________ */ static int parse_rhs() /* */ { /* */ int start_flno = flno; /* */ /* */ sbrewind(parse_sb); /* */ do /* */ { if ( sbtell(parse_sb) != 0 ) /* */ { (void)sbputs(" # ",parse_sb); } /* */ /* */ switch ( GetC ) /* */ { case EOF: /* */ UnterminatedError("Unterminated value", /* */ start_flno); /* */ return(FALSE); /* */ /* */ case '"': /* */ if ( !parse_string(TRUE) ) return(FALSE); /* */ break; /* */ /* */ case '{': /* */ if ( !parse_block(TRUE) ) return(FALSE); /* */ break; /* */ /* */ case '0': case '1': case '2': case '3': case '4':/* */ case '5': case '6': case '7': case '8': case '9':/* */ UnGetC; /* */ parse_number(); /* */ (void)sbputs((char*)pop_string(),parse_sb);/* */ break; /* */ /* */ default: /* */ UnGetC; /* */ ExpectSymbol(TRUE,FALSE); /* */ { register String mac; /* */ mac = pop_string(); /* */ #ifdef OLD (void)look_macro(mac,1); /* */ #endif (void)sbputs((char*)mac,parse_sb); /* */ } /* */ } /* */ } while ( GetC == '#' ); /* */ /* */ push_string(symbol((String)sbflush(parse_sb))); /* */ sbrewind(parse_sb); /* */ UnGetC; return(TRUE); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_equation() ** Purpose: Parse a pair separated by an equals sign. ** ** Arguments: ** rec The record to store the result in ** Returns: Success status **___________________________________________________ */ static int parse_equation(rec) /* */ Record rec; /* */ { String s, t; /* */ /* */ ExpectSymbol(TRUE,FALSE); /* */ Expect('=',FALSE); /* */ ExpectRhs(FALSE); /* */ /* */ t = pop_string(); /* */ s = pop_string(); /* */ push_to_record(rec,s,t); /* */ return(TRUE); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_bib() ** Purpose: Read one entry and fill the internal record structure. ** Return the type of the entry read. ** ** |BIB_EOF| is returned if nothing could be read and ** the end of the file has been encountered. ** ** |BIB_NOOP| is returned when an error has occurred. This is ** an indicator that no record has been read but the ** error recovery is ready to try it again. ** ** This function is for internal purposes mainly. See ** |read_db()| for a higher level function to read a ** database. ** Arguments: ** rec Record to store the result in. ** Returns: The type of the entry read, |BIB_EOF|, or |BIB_NOOP|. **___________________________________________________ */ int parse_bib(rec) /* */ Record rec; /* */ { register int type, /* */ n, /* */ c, /* */ om; /* */ long ignored = 0L; /* */ char *name; /* */ int line; /* */ char buffer[32]; /* */ static StringBuffer * comment_sb = (StringBuffer*)NULL;/* */ /* */ if ( file == NULL ) return BIB_EOF; /* */ if ( comment_sb == (StringBuffer*)NULL ) /* */ { comment_sb = sbopen(); } /* */ /* */ RecordOldKey(rec) = NULL; /* */ RecordFree(rec) = 0; /* */ RecordComment(rec) = sym_empty; /* */ /* */ do /* */ { init_parse(); /* */ /* */ while ( (c=skip_c()) != '@' ) /* Skip to next @ */ { if ( c == EOF ) /* */ { char *s, *t; /* */ if ( ignored == 0 ) return(BIB_EOF); /* */ RecordType(rec) = BIB_COMMENT; /* */ /* */ s = t = sbflush(comment_sb); /* */ while ( *s ) s++; /* */ while ( t <= --s && is_space(*s) ) *s = '\0';/* */ if ( *t ) RecordComment(rec) = symbol((String)t);/* */ sbrewind(comment_sb); /* */ return(BIB_COMMENT); /* */ } /* */ if ( !is_space(c) ) ++ignored; /* */ if ( ignored > 0 && rsc_pass_comment ) /* */ { sbputchar(c,comment_sb); } /* */ } /* */ /* */ if ( ignored != 0L ) /* */ { if ( rsc_pass_comment ) /* */ { sbputchar('\n',comment_sb); } /* */ else /* */ { (void)sprintf(buffer,"%ld",ignored); /* */ error(ERR_WARN|ERR_FILE,(String)buffer, /* */ (String)" non-space characters ignored.",/* */ StringNULL,StringNULL,StringNULL, /* */ flno,filename); /* */ } /* */ } /* */ /* */ if ( (type=find_entry_type(flp)) == BIB_NOOP ) /* */ { Error("Unknown entry type"); /* */ return(BIB_NOOP); /* */ } /* */ flp += strlen((char*)EntryName(type)); /* */ /* */ if ( type == BIB_COMMENT && rsc_pass_comment ) /* */ { sbputchar('@', comment_sb); /* */ sbputs((char*)EntryName(type), comment_sb); /* */ } /* */ } while (type == BIB_COMMENT); /* */ /* */ c = GetC; /* */ if ( c != '{' && c != '(' ) /* */ { Error("Expected '{' or '(' missing"); /* */ return(BIB_NOOP); /* */ } /* */ line = flno; /* */ name = filename; /* */ /* */ RecordType(rec) = type; /* */ /* */ switch ( type ) /* */ { case BIB_COMMENT: /* This code is not used */ UnGetC; /* any more. */ (void)parse_rhs(); /* */ push_to_record(rec,pop_string(),StringNULL); /* */ return type; /* */ /* */ case BIB_PREAMBLE: /* */ ExpectRhs(BIB_NOOP); /* */ push_to_record(rec,pop_string(),StringNULL); /* */ break; /* */ /* */ case BIB_STRING: /* */ ExpectEqMac(rec,BIB_NOOP); /* */ break; /* */ /* */ case BIB_ALIAS: /* */ ExpectEq(rec,BIB_NOOP); /* */ break; /* */ /* */ case BIB_INCLUDE: /* */ ExpectRhs(BIB_NOOP); /* */ push_to_record(rec,pop_string(),StringNULL); /* */ break; /* */ /* */ case BIB_MODIFY: /* */ default: /* */ if ( TestC == ',' ) /* */ { Warning("Missing reference key"); /* */ push_to_record(rec,sym_empty,StringNULL); /* */ (void)GetC; /* */ } /* */ else /* */ { ExpectKey(FALSE,BIB_NOOP); /* */ Expect(',',BIB_NOOP); /* */ push_to_record(rec,pop_string(),StringNULL); /* */ } /* */ /* */ do /* */ { ExpectEq(rec,BIB_NOOP); /* */ for( n=0; GetC==','; n++) /* */ { if ( n == 1 ) /* */ { Warning("Multiple ',' ignored."); } /* */ } /* */ UnGetC; /* */ switch (TestC) /* */ { case EOF: /* */ case '}': /* */ case ')': om = FALSE; break; /* */ default: om = TRUE; /* */ if ( n == 0 ) /* */ { Warning("Missing ',' assumed."); } /* */ } /* */ } while ( om ); /* */ } /* */ /* */ switch ( GetC ) /* */ { case '}': /* */ if( c != '{' ) /* */ { Warning("Parenthesis '(' closed by '}'"); }/* */ break; /* */ case ')': /* */ if( c != '(' ) /* */ { Warning("Parenthesis '{' closed by ')'"); }/* */ break; /* */ case EOF: /* */ { char *s; /* */ if (c == '{') { s = "'{'"; } /* */ else { s = "'('"; } /* */ error(ERR_ERROR|ERR_FILE,(String)s, /* */ (String)" not closed at end of file.",/* */ StringNULL,StringNULL,StringNULL, /* */ line,name); /* */ } /* */ break; /* */ default: /* */ { String s; /* */ if (c == '{') { s = (String)"'{'"; } /* */ else { s = (String)"'('"; } /* */ error(ERR_ERROR|ERR_FILE, /* */ s, /* */ (String)" not properly terminated.", /* */ StringNULL,StringNULL,StringNULL, /* */ line,name); /* */ } /* */ return(BIB_NOOP); /* */ } /* */ /* */ { char *s, *t; /* */ s = t = sbflush(comment_sb); /* */ while ( *s ) s++; /* */ while ( t <= --s && is_space(*s) ) *s = '\0'; /* */ if ( *t ) RecordComment(rec) = (String)symbol((String)t);/* */ } /* */ sbrewind(comment_sb); /* */ return(type); /* */ } /*------------------------*/ /*****************************************************************************/ /* */ /*****************************************************************************/ static char **r_path = (char**)0; static char *r_pattern[] = { "%s/%s", "%s/%s.rsc", NULL }; /*----------------------------------------------------------------------------- ** Function: set_rsc_path() ** Purpose: Initialize the resource file reading apparatus. ** Primarily try to figure out the file search path. ** Arguments: ** val The string representation of the file search path. ** Returns: nothing **___________________________________________________ */ void set_rsc_path(val) /* */ String val; /* */ { /* */ rsc_v_rsc = val; /* */ init___(&r_path, /* */ r_pattern, /* */ (char**)&rsc_v_rsc, /* */ (char*)rsc_e_rsc ); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: see_rsc() ** Purpose: Open a rsc file to read from. The resource file path ** and the optional extensions are used to construct the ** full file name. ** Arguments: ** fname The file name to take into account. ** Returns: |TRUE| iff the operation succeeds. **___________________________________________________ */ static int see_rsc(fname) /* */ String fname; /* */ { /* */ if ( fname ) /* */ { init_parse(); /* */ InitLine; /* */ file = px_fopen((char*)fname, /* */ "r", /* */ r_pattern, /* */ r_path, /* */ see_bib_msg); /* */ filename = px_filename; /* */ return( file != NULL ); /* */ } /* */ return FALSE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: parse_value() ** Purpose: ** ** ** Arguments: ** ** Returns: **___________________________________________________ */ static int parse_value() /* */ { /* */ int start_flno = flno; /* */ /* */ sbrewind(parse_sb); /* */ switch ( GetC ) /* */ { case EOF: /* */ UnterminatedError("Unterminated value", /* */ start_flno); /* */ return FALSE; /* */ /* */ case '"': /* */ if ( !parse_string(FALSE) ) return(FALSE); /* */ push_string(symbol((String)sbflush(parse_sb)));/* */ sbrewind(parse_sb); /* */ break; /* */ /* */ case '0': case '1': case '2': case '3': case '4':/* */ case '5': case '6': case '7': case '8': case '9':/* */ UnGetC; parse_number(); /* */ break; /* */ /* */ case '{': /* */ if ( !parse_block(FALSE) ) return FALSE; /* */ push_string(symbol((String)sbflush(parse_sb)));/* */ sbrewind(parse_sb); /* */ break; /* */ /* */ default: /* */ UnGetC; ExpectSymbol(TRUE,FALSE); /* */ } /* */ /* */ return TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: read_rsc() ** Purpose: Read a resource file and evaluate all instructions ** contained. ** ** The characters |#|, |%|, and |;| start an endline ** comment but only between resource instructions. They ** are not recognized between a resource instruction ** and its value or inside the value braces. ** ** This function is contained in this module because it ** shares several functions with the \BibTeX{} parsing ** routines. ** Arguments: ** name Name of the file to read from. ** Returns: **___________________________________________________ */ int read_rsc(name) /* */ String name; /* */ { int c; /* */ String token; /* */ char *s_filename; /* */ FILE *s_file; /* */ String s_file_line_buffer; /* */ size_t s_fl_size; /* */ int s_flno; /* */ String s_flp; /* */ /* Save the old state in */ /* local variables to */ /* restore it later. */ s_filename = filename; /* */ s_file = file; /* */ s_file_line_buffer = file_line_buffer; /* */ s_fl_size = fl_size; /* */ s_flno = flno; /* */ s_flp = flp; /* */ /* */ fl_size = 0; /* */ /* */ init_parse(); /* */ /* */ if ( see_rsc(name) ) /* */ { /* */ while ( (c=TestC) != EOF ) /* */ { switch (c) /* */ { case '#': case '%': case ';': /* */ ClearLine; break; /* */ default: /* */ if ( !parse_symbol(c) ) /* */ { (void)seen(); return(1); } /* */ token = pop_string(); /* */ if ( TestC == '=' ) (void)GetC; /* = is optional */ if ( !parse_value() ) /* */ { (void)seen(); /* */ return(-1); /* */ } /* */ (void)set_rsc(token,pop_string()); /* */ } /* */ } /* */ (void)seen(); /* */ c = TRUE; /* */ } /* */ else /* */ { c = FALSE; /* */ } /* */ if ( fl_size > 0 ) /* */ { free((char*)file_line_buffer); /* */ } /* */ filename = s_filename; /* */ file = s_file; /* */ file_line_buffer = s_file_line_buffer; /* */ fl_size = s_fl_size; /* */ flno = s_flno; /* */ flp = s_flp; /* */ /* */ return c; /* */ } /*------------------------*/ BibTool/print.c0000644000175100017510000006632612646457543012365 0ustar genegene/*** print.c ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module provides also access to the functions and ** variables defined in |entry.c|. Consult also the documentation ** of this file for details. ** ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif char * sput_record _ARG((Record rec,DB db,String start));/* print.c */ static int fput_char _ARG((int c)); /* print.c */ static int sput_char _ARG((int c)); /* print.c */ static void indent _ARG((int col,int (*fct)_ARG((int))));/* print.c */ static void line_breaking _ARG((String t,int align,int (*fct)_ARG((int))));/* print.c*/ static void print_equation _ARG((String pre,String s,String t,int align,int (*fct)_ARG((int))));/* print.c*/ static void puts_in _ARG((String s,int in,int (*fct)_ARG((int))));/* print.c */ void fput_record _ARG((FILE *file,Record rec,DB db,String start));/* print.c*/ void put_record _ARG((int (*fct)_ARG((int)),Record rec,DB db,String start));/* print.c*/ void set_key_type _ARG((String s)); /* print.c */ void set_symbol_type _ARG((String s)); /* print.c */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ #define TAB_WIDTH 8 static int symbol_type = SYMBOL_TYPE_LOWER; /* */ static String s_upper = (String)"upper"; /* */ static String s_lower = (String)"lower"; /* */ static String s_cased = (String)"cased"; /* */ /*----------------------------------------------------------------------------- ** Function: set_symbol_type() ** Purpose: Function to set the symbol type which is used by the ** printing routine. The argument is a string describing ** the value to use. Possible values are |"upper"|, ** |"lower"|, and |"cased"|. The comparison of the values ** is performed case insensitive. ** ** If no appropriate value is found then an error message ** is issued as the only action. ** ** This function is called from |rsc.c|. ** Arguments: ** s String description of the value. ** Returns: nothing **___________________________________________________ */ void set_symbol_type(s) /* */ register String s; /* */ { if ( case_cmp(s, s_upper) ) /* */ { symbol_type = SYMBOL_TYPE_UPPER; } /* */ else if ( case_cmp(s, s_cased) ) /* */ { symbol_type = SYMBOL_TYPE_CASED; } /* */ else if ( case_cmp(s, s_lower) ) /* */ { symbol_type = SYMBOL_TYPE_LOWER; } /* */ else /* */ { Err("Unknown symbol type ignored.\n"); } /* */ } /*------------------------*/ #ifdef MAYBE_IN_THE_NEXT_RELEASE static int key_type = SYMBOL_TYPE_LOWER; /* */ /*----------------------------------------------------------------------------- ** Function*: set_key_type() ** Purpose: Wrapper function to set the static variable key_type. ** This function is called from rsc.c ** Arguments: ** s String description of the value. ** Returns: nothing **___________________________________________________ */ void set_key_type(s) /* */ register String s; /* */ { if ( case_cmp(s,s_upper) ) /* */ { key_type = SYMBOL_TYPE_UPPER; } /* */ else if ( case_cmp(s,s_cased) ) /* */ { key_type = SYMBOL_TYPE_CASED; } /* */ else if ( case_cmp(s,s_lower) ) /* */ { key_type = SYMBOL_TYPE_LOWER; } /* */ else /* */ { Err("Unknown key type ignored.\n"); } /* */ } /*------------------------*/ #endif /*------------------------*/ static int column = 0; /* The current column of */ /* the output stream is */ /* kept in this variable.*/ #define NL (void)(*fct)('\n'),column=0 #define PUTC(C) (void)((*fct)(C),++column) #define PUTS(S) puts_in((String)S, 0, fct) /*----------------------------------------------------------------------------- ** Function: puts_in() ** Purpose: Print a string and update current column. ** Arguments: ** s string to be printed. ** in indentation. Alignment column. ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________ */ static void puts_in(s,in,fct) /* */ register String s; /* */ register int in; /* */ int (*fct)_ARG((int)); /* */ { /* */ while ( *s ) /* */ { (void)(*fct)(*s); /* */ switch ( *(s++) ) /* */ { case '\t': /* */ column += TAB_WIDTH - (column%TAB_WIDTH); /* */ break; /* */ case '\n': /* */ column = 0; /* */ if ( in > 0 ) indent(in, fct); /* */ break; /* */ default: ++column; /* */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: indent() ** Purpose: Add spaces or tabs to indent to the given column. ** If the current column is beyond col then nothing happens. ** The resource use.tabs can be used to disable the use of TAB. ** Arguments: ** col Target column ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________ */ static void indent(col,fct) /* */ register int col; /* */ int (*fct)_ARG((int)); /* */ { /* */ if ( col > rsc_linelen ) col = rsc_linelen; /* */ while ( column < col ) /* */ { if ( rsc_use_tabs /* TAB is allowed and */ && column+TAB_WIDTH-(column%TAB_WIDTH) <= col )/* enough space left */ { (void)(*fct)('\t'); /* then put a TAB and */ column += TAB_WIDTH - (column%TAB_WIDTH); /* update column. */ } /* */ else /* otherwise */ { (void)(*fct)(' '); /* write a single space */ ++column; /* and advance column. */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: line_breaking() ** Purpose: Write out a right hand side of an equation. ** If it does not fit break the line into several parts and ** print them on successive lines. ** Temporarily end marks are placed inside the string, ** but the old contents has been restored at the end. ** Arguments: ** t string to print. ** align starting column for continuation lines. ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________ */ static void line_breaking(t, align, fct) /* */ register String t; /* string to print. */ int align; /* alignment column */ int (*fct)_ARG((int)); /* */ { register String s; /* intermediate pointer */ char end_c; /* temp. character. */ int brace, /* brace counter */ len, /* length of rem. output */ first = TRUE; /* indicator for # */ /* */ while ( is_space(*t) ) ++t; /* skip leading spaces */ /* */ indent(align, fct); /* goto alignment column */ /* */ while ( *t ) /* as long as sth to print*/ { s = t; /* */ /* */ switch ( *t ) /* */ { case '"': /* QUOTED PART */ for ( len = 2, ++t; /* */ *t && *t != '\"'; /* Search terminating " */ ++t, ++len ) /* */ { if ( *t == '\\' && *(t+1) != '\0' ) /* skip over quoted and */ { ++t; ++len; } /* similar constructs. */ } /* */ if ( *t ) ++t; /* skip after end, if poss*/ if ( *t ) { end_c = *t; *t = '\0'; } /* save char and mark end.*/ else { end_c = *t; } /* */ break; /* */ case '{': /* BRACED PART */ brace = 1; /* */ for ( len = 2, ++t; /* find matching brace. */ *t && brace > 0; /* */ ++t, ++len ) /* */ { switch ( *t ) /* */ { case '\\': if ( *(t+1) ) ++t; break; /* ignore \{ \} etc */ case '{': ++brace; break; /* */ case '}': brace--; break; /* */ } /* */ } /* */ if ( *t ) { end_c = *t; *t = '\0'; } /* save char and mark end.*/ else { end_c = *t; } /* */ break; /* */ default: /* Now we should have a */ while ( is_allowed(*t) ) ++t; /* SYMBOL */ end_c = *t; *t = '\0'; /* */ s = get_item(symbol(s), symbol_type); /* */ len = strlen((char*)s); /* */ } /* */ /* Now s is a single */ /* string to print. */ /* t points to the closing*/ /* '\0' of s */ /* end_c is the old *t */ while ( *s ) /* */ { if ( len + (first?0:3) <= rsc_linelen - column)/* Is there enough space*/ { if ( !first ) PUTS(" # "); /* Maybe add separator */ puts_in(s, align, fct); /* write it out */ s = t; /* and we are done */ } /* */ else if ( !first ) /* If sth has been before */ { puts_in((String)"\n# ", align - 2, fct); /* start a new line */ first = TRUE; /* */ } /* Now we have to break */ else /* a single entry */ { Uchar save_c; /* */ String save_ptr, /* */ ptr; /* */ /* */ if ( 0 <= rsc_linelen - column ) /* */ save_ptr = s + rsc_linelen - column; /* Potential end */ else /* */ save_ptr = s; /* */ /* */ for ( ptr = s; /* Search next newline */ ptr < save_ptr && *ptr != '\n'; /* or end of region */ ptr++ ) {} /* */ /* */ if ( *ptr == '\n' ) /* */ { save_ptr = ptr; /* */ *save_ptr = '\0'; /* Save and mark end. */ puts_in(s, align, fct); /* */ NL; /* */ indent(align,fct); /* */ *save_ptr = '\n'; /* Restore end */ len += s - save_ptr - 1; /* Update the length */ s = save_ptr + 1; /* */ } /* */ else /* */ { /* */ while ( save_ptr != s && *save_ptr != ' ' )/* */ { save_ptr--; } /* Find a SPC backward */ /* */ if ( save_ptr == s ) /* If no SPC found then */ { while ( *save_ptr && *save_ptr != ' ' )/* search one forward. */ { save_ptr++; } /* */ } /* */ len += s - save_ptr; /* Update the length */ save_c = *save_ptr; *save_ptr = '\0'; /* Save and mark end. */ puts_in(s, align, fct); /* */ if (save_c != 0) /* */ { NL; /* */ indent(align, fct); /* */ } /* */ *save_ptr = save_c; /* Restore end */ s = save_ptr; /* */ while ( is_space(*s) ) { s++; len--; } /* Skip spaces */ } /* */ } /* */ } /* */ *t = end_c; /* Restore the end */ /* */ while ( *t && *t != '#' ) ++t; /* Search next # */ if ( *t ) ++t; /* Skip beyond the # */ while ( is_space(*t) ) ++t; /* Ignore following spaces*/ first = FALSE; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: print_equation() ** Purpose: Print something of the form s = t ** If desired it can be indented. t is broken if it doesn't fit ** in one line. ** Arguments: ** pre string to be printed before s. ** s left hand side ** t right hand side ** align target column. If negative no indentation is performed. ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________' */ static void print_equation(pre, s, t, align, fct) /* */ String pre; /* */ String s; /* */ String t; /* */ int align; /* */ int (*fct)_ARG((int)); /* */ { /* */ if ( align < 0 ) /* */ { PUTS(pre); /* */ PUTS(get_item(s,symbol_type)); /* */ if ( rsc_print_we ) /* */ { PUTS(" = "); } /* */ else /* */ { PUTC('='); } /* */ PUTS(t); /* */ } /* */ else /* */ { indent(rsc_indent,fct); /* */ PUTS(pre); /* */ PUTS(get_item(s,symbol_type)); /* */ if ( column >= align - 2 && rsc_print_we ) /* */ { PUTC(' '); } /* */ else if ( rsc_eq_right ) /* */ { indent(align-2,fct); } /* */ else if ( column < align || rsc_print_we ) /* */ { PUTC(' '); } /* */ PUTC('='); /* */ if ( rsc_print_we ) { PUTC(' '); } /* */ line_breaking(t,align,fct); /* */ } /* */ } /*------------------------*/ static FILE * ofile=NULL; /*----------------------------------------------------------------------------- ** Function: fput_char() ** Purpose: Output function which places the character on the |ofile| ** stream. ** Arguments: ** c Character to print. ** Returns: The return status of |fputc()|. **___________________________________________________ */ static int fput_char(c) /* */ int c; /* */ { return fputc(c, ofile); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fput_record() ** Purpose: Format and print a complete record onto a given stream. ** for further details see |put_record()|. ** Arguments: ** file Stream to print onto. ** db Database containing the record. ** rec Record to print. ** start Initial string used before the type. Should be "@" normally. ** Returns: nothing **___________________________________________________ */ void fput_record(file, rec, db, start) /* */ FILE *file; /* */ DB db; /* */ Record rec; /* record to print */ String start; /* initial string = "@" */ { /* */ ofile = file; /* */ put_record(fput_char, rec, db, start); /* */ } /*------------------------*/ static StringBuffer *osb = NULL; /*----------------------------------------------------------------------------- ** Function: sput_char() ** Purpose: Output function which places the character on the |osb| ** string buffer. ** Arguments: ** c Character to print. ** Returns: The return status of |fputc()|. **___________________________________________________ */ static int sput_char(c) /* */ int c; /* */ { return sbputchar(c, osb); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sput_record() ** Purpose: Format and print a complete record into a string and return it. ** The string returned points to static memory which is ** reused upon the next invocation of this function. ** Arguments: ** file Stream to print onto. ** db Database containing the record. ** rec Record to print. ** start Initial string used before the type. Should be "@" normally. ** Returns: The string containing the printed representation. **___________________________________________________ */ char * sput_record(rec, db, start) /* */ DB db; /* */ Record rec; /* record to print */ String start; /* initial string = "@" */ { /* */ if ( osb == NULL ) osb = sbopen(); /* */ sbrewind(osb); /* */ put_record(sput_char, rec, db, start); /* */ return sbflush(osb); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: put_record() ** Purpose: Format and print a complete record. ** The record type and several resources are taken into ** account. The following external variables (from ** |rsc.c|) are taken into account: ** \begin{description} ** \item[rsc\_parentheses] If this boolean variable is ** |TRUE| then |(| and |)| are used to delimit the ** record. Otherwise |{| and |}| are used. ** \item[rsc\_col\_p] This integer variable controls the ** indentation of preamble records. ** \item[rsc\_col\_s] This integer variable controls the ** indentation of string records. ** ** \item[rsc\_expand\_macros] If this boolean variable is ** set then macros are expanded before the record is ** printed. This does not effect the internal ** representation. ** \item[rsc\_col] This integer variable controls the ** indentation of normal records. ** \item[rsc\_col\_key] This integer variable controls the ** indentation of the key in a normal record. ** \item[rsc\_newlines] This integer variable controls ** the number of newlines printed after a normal record. ** ** \item[rsc\_linelen] This integer variable controls ** the length of the line. The line breaking algorithm ** is applied if this column is about to be violated. ** \item[rsc\_indent] This integer variable controls the ** indentation of equations. ** \item[rsc\_eq\_right] This boolean variable controls ** the alignment of the |=| in equations. It it is set ** then the equality sign is flushed right. Otherwise it ** is flushed left. ** \end{description} ** ** The field in the record are sorted with ** |sort_record()| before they are printed. ** ** In normal records all fields not starting with an ** allowed character are ignored. Thus it is possible to ** store private and invisible information in a ** field. Simply start the field name with an not allowed ** character like |%|. ** Arguments: ** fct function to use for writing a character. ** db Database containing the record. ** rec Record to print. ** start Initial string used before the type. Should be "@" normally. ** Returns: nothing **___________________________________________________ */ void put_record(fct, rec, db, start) /* */ int (*fct)_ARG((int)); /* */ Record rec; /* */ DB db; /* */ String start; /* initial string = "@" */ { String *hp; /* heap pointer */ unsigned int i; /* */ char open_brace, close_brace; /* */ static int first = 1; /* */ /* */ sort_record(rec); /* */ /* */ hp = RecordHeap(rec); /* */ if ( rsc_no_nl && first ) { first = 0; } /* */ else if ( IsNormalRecord(RecordType(rec)) ) { NL; }/* */ /* */ if ( *RecordComment(rec) ) /* */ { PUTS(RecordComment(rec)); /* */ NL; /* */ } /* */ /* */ if ( rsc_parentheses ) /* */ { open_brace = '('; /* */ close_brace = ')'; /* */ } /* */ else /* */ { open_brace = '{'; /* */ close_brace = '}'; /* */ } /* */ /* */ switch ( RecordType(rec) ) /* */ { case BIB_COMMENT: /* */ #ifdef OLD indent(rsc_col_c, fct); /* */ PUTS(*hp); /* */ PUTC(' '); /* */ NL; /* */ #endif break; /* */ case BIB_PREAMBLE: /* */ PUTS(start); /* */ PUTS(EntryName(RecordType(rec))); /* */ PUTC(open_brace); /* */ indent(rsc_col_p,fct); /* */ line_breaking(*hp, rsc_col_p, fct); /* */ PUTC(' '); /* */ PUTC(close_brace); /* */ NL; /* */ break; /* */ case BIB_STRING: /* */ PUTS(start); /* */ PUTS(EntryName(RecordType(rec))); /* */ PUTC(open_brace); /* */ print_equation(sym_empty, /* */ *hp, *(hp+1), rsc_col_s, fct);/* */ PUTC(' '); /* */ PUTC(close_brace); /* */ NL; /* */ break; /* */ case BIB_ALIAS: /* */ PUTS(start); /* */ PUTS(EntryName(RecordType(rec))); /* */ PUTC(open_brace); /* */ print_equation(sym_empty, /* */ *hp, *(hp+1), rsc_col_s, fct);/* */ PUTC(' '); /* */ PUTC(close_brace); /* */ NL; /* */ break; /* */ case BIB_INCLUDE: /* */ PUTS(start); /* */ PUTS(EntryName(RecordType(rec))); /* */ PUTC(open_brace); /* */ PUTS(*RecordHeap(rec)); /* */ PUTC(close_brace); /* */ NL; /* */ break; /* */ case BIB_MODIFY: /* */ default: /* */ PUTS(start); /* */ PUTS(EntryName(RecordType(rec))); /* */ PUTC(open_brace); /* */ { String comma1 = sym_empty, /* */ comma2 = (String)","; /* */ /* */ if (rsc_print_ce) /* */ { comma1 = comma2; /* */ comma2 = sym_empty; /* */ } /* */ /* */ for ( i = RecordFree(rec); i > 0; i -= 2 ) /* */ { /* No deleted or */ if ( *hp && is_allowed(**hp) ) /* private entry */ { /* */ if ( *(hp+1) ) /* If equation */ { PUTS(comma1); /* */ NL; /* */ print_equation(comma2, /* */ *hp, /* */ (rsc_expand_macros /* */ ? expand_rhs(*(hp+1),/* */ (String)(rsc_braces?"{":"\""),/* */ (String)(rsc_braces?"}":"\""),/* */ db) /* */ : *(hp+1) ), /* */ rsc_col, /* */ fct); /* */ } /* */ else /* Otherwise print a key */ { indent(rsc_col_key, fct); /* */ PUTS(get_key_name(*hp)); /* */ } /* */ } /* */ hp += 2; /* Goto next pair. */ } /* */ } /* */ if (rsc_print_tc) { PUTC(','); } /* */ NL; /* */ PUTC(close_brace); /* */ for ( i = rsc_newlines; i > 0; --i ) { NL; } /* */ } /* */ } /*------------------------*/ BibTool/pxfile.c0000644000175100017510000003653412646457552012516 0ustar genegene/*** pxfile.c ***************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This file provides routines for extended file opening. Files ** are sought in a list of directories and optionally with a set ** of extensions appended to them. ** ** Patterns may be given which are used to determine the full file ** name. ** The patterns are stored in a special data structure. A ** function is provided to allocate a pattern structure and fill ** it from a string specification. ** ******************************************************************************/ #include "config.h" #include #include #include #include #ifndef __STDC__ #ifndef HAVE_GETENV extern char * getenv _ARG((char* name)); /* */ #endif #endif #ifndef DEFAULT_PATTERN #ifdef MSDOS #define DEFAULT_PATTERN "%s\\%s" #else #define DEFAULT_PATTERN "%s/%s" #endif #endif /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif FILE * px_fopen _ARG((char * name,char * mode,char **pattern,char **path,int (*show)_ARG((char*)))); char ** px_s2p _ARG((char * s,int sep)); static int absolute_file _ARG((char *name,char **basename,char ***path)); static void expand_env _ARG((char * s,char * se,StringBuffer * res)); /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Variable: px_filename ** Purpose: This variable contains the file name actually used by ** the last |px_fopen()| call. The memory is automatically ** managed and will be reused by the next call to ** |px_fopen()|. Thus if you need to use it make a ** private copy immediately after the call to the ** function |px_fopen()|. **___________________________________________________ */ char *px_filename = "" ; static size_t px_len = 0 ; static char * no_path[] = { "." , NULL }; static char * no_pattern[] = { DEFAULT_PATTERN, NULL }; /*----------------------------------------------------------------------------- ** Function: absolute_file() ** Purpose: Check is the file is an absolute file name. ** In this case make a new path array which contains the absolute ** path only and its location in path. basename is the modified ** file name. The return value is TRUE ** Otherwise FALSE is returned and nothing changed. ** ** Currently UN*X and MSDOS like file names are supported. ** Arguments: ** name ** basename ** path ** Returns: **___________________________________________________ */ static int absolute_file(name,basename,path) /* */ char *name; /* */ char **basename; /* */ char ***path; /* */ { static char *absolut_path[2]; /* */ static int first = (-1); /* */ int l; /* */ char *sp; /* */ #undef SEPARATOR /* */ #ifdef MSDOS #define SEPARATOR '\\' if ( *name != SEPARATOR /* starting with root or */ && ( *name == '\0' /* */ || *(name+1) != ':' /* */ || *(name+2) != SEPARATOR ) ) /* with drive */ #endif #ifdef AMIGA #define SEPARATOR '/' if ( strchr(name,':') == NULL ) /* starting with root */ #endif #ifndef SEPARATOR #define SEPARATOR '/' if ( *name != SEPARATOR ) /* starting with root */ #endif { return 0; } /* */ /* */ sp = strrchr(name,SEPARATOR); /* find last separator */ /* existence guarenteed! */ #ifdef AMIGA if ( sp == NULL ) sp = strchr(name,':'); /* */ #endif l = (int)(sp-name); /* length of directory. */ if ( first ) /* */ { first = 0; /* */ absolut_path[1] = NULL; /* mark end of array. */ absolut_path[0] = malloc(l+1); /* allocate */ } /* or */ else /* reallocate */ { absolut_path[0] = realloc(*absolut_path,l+1); /* space for the */ } /* directory name */ /* */ (void)strncpy(absolut_path[0],name,l); /* save directory name */ *(absolut_path[0]+l) = '\0'; /* and mark the end. */ /* */ *basename = name+l+1; /* return the base name */ *path = absolut_path; /* return the path array */ /* */ return 1; /* finished. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: px_fopen() ** Purpose: Open a file using path and pattern. ** ** ** Arguments: ** name (base) name of the file to open. ** mode Mode for opening the file like used with |fopen()|. ** pattern A |NULL| terminated array of patterns. ** path The |NULL| terminated array of directories. ** show A function pointer or |NULL|. ** Returns: A file pointer refering to the file or |NULL|. **___________________________________________________ */ FILE * px_fopen(name,mode,pattern,path,show) /* */ char * name; /* */ char * mode; /* */ char **pattern; /* */ char **path; /* */ int (*show)_ARG((char*)); /* */ { char **fmt; /* */ char **pp; /* */ FILE * file; /* */ size_t len,plen; /* */ char **new_path; /* */ char *new_name; /* */ /* */ if ( path == NULL ) path = no_path; /* use default path */ if ( pattern == NULL ) pattern = no_pattern; /* use default pattern */ /* */ if ( absolute_file(name,&new_name,&new_path) ) /* */ { name = new_name; /* */ path = new_path; /* */ } /* */ /* */ for ( plen=0,fmt=pattern;*fmt;++fmt ) /* compute longest */ { len = strlen(*fmt); /* pattern */ if ( len > plen ) plen = len; /* */ } /* */ plen += 1+strlen(name); /* add length of name */ /* and 1 for '\0' */ if ( px_len == 0 && /* initial filename */ (px_filename = malloc(plen))==NULL ) /* then allocate or */ return(NULL); /* terminate */ px_len = plen-1; /* usable is 1 less */ /* */ for ( pp=path;*pp;++pp ) /* use all paths */ { len = strlen(*pp) + plen; /* required space */ if ( px_len < len ) /* if less present get it */ { char * old = px_filename; /* */ if ( (px_filename = realloc(px_filename,len))==NULL ) {/* */ free(old); /* */ return(NULL); /* */ } /* */ px_len = len-1; /* usable is 1 less */ } /* */ /* */ for ( fmt=pattern;*fmt;++fmt ) /* use all patterns */ { (void)sprintf(px_filename,*fmt,*pp,name); /* construct new filename */ if ( ( show == NULL || /* if function present */ (*show)(px_filename) ) && /* and it says yes */ (file=fopen(px_filename,mode)) != NULL )/* and open succeeds */ return(file); /* then return file ptr */ } /* */ } /* */ *px_filename = '\0'; /* clear filename */ return(NULL); /* failure */ } /*------------------------*/ #define INIT_SIZE 32 #define INC_SIZE 16 /*----------------------------------------------------------------------------- ** Function: px_s2p() ** Purpose: Translate a path string specification into an array of the ** components. ** The memory of the array is malloced and should be freed when ** not used any longer. ** Arguments: ** s String to analyze ** sep Separator ** Returns: The array of the components **___________________________________________________ */ char ** px_s2p(s,sep) /* */ char * s; /* */ int sep; /* */ { register char *cp; /* */ register size_t l = 1; /* */ char **pattern; /* */ int *array; /* */ size_t array_size = INIT_SIZE; /* */ size_t array_ptr = 0; /* */ char *t; /* */ StringBuffer *sb; /* */ /* */ if ( s == NULL ) return(NULL); /* No string to analyze */ /* */ if ( (array=(int*)malloc(array_size*sizeof(int)))/* */ == NULL ) /* */ { return NULL; } /* */ /* */ t = cp = s; /* */ sb = sbopen(); /* */ for(;;) /* Count the number of */ { /* fields and expand */ if ( *cp == sep || *cp == '\0' ) /* */ { if ( array_ptr >= array_size ) /* */ { array_size += INC_SIZE; /* */ int* old = array; /* */ array = (int*)realloc(array, /* */ array_size*sizeof(int));/* */ if ( array == NULL ) { /* */ free(old); /* */ return NULL; /* */ } /* */ } /* */ array[array_ptr++] = sbtell(sb); /* */ expand_env(t,cp,sb); /* */ sbputchar('\0',sb); /* */ t = cp+1; /* */ if ( *cp ) cp++; /* */ else break; /* */ } /* */ else /* */ { cp++; /* */ } /* */ } /* */ /* */ l = sbtell(sb); /* */ s = sbflush(sb); /* */ /* */ if ( (pattern=(char**)malloc( (array_ptr+1)*sizeof(char*)/* */ +l*sizeof(char))) /* */ == (char**)NULL ) /* Try to allocate space */ { return NULL; } /* */ /* */ cp = (char*)&pattern[array_ptr+1]; /* */ (void)memcpy(cp,s,l); /* save the string spec */ /* */ for ( l = 0; l < array_ptr; l++ ) /* */ { pattern[l] = cp + array[l]; } /* */ pattern[array_ptr] = 0L; /* Mark end */ /* */ (void)free(array); /* */ sbclose(sb); /* */ return pattern; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: expand_env() ** Type: static char * ** Purpose: ** ** Arguments: ** s ** se ** Returns: **___________________________________________________ */ static void expand_env(s,se,res) /* */ char * s; /* */ char * se; /* */ StringBuffer * res; /* */ { /* */ StringBuffer * val = sbopen(); /* */ /* */ for ( ; s #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif Record copy_record _ARG((Record rec)); Record new_record _ARG((int token,int size)); Record record_gc _ARG((Record rec)); Record unlink_record _ARG((Record rec)); WordList new_wordlist _ARG((String s)); void add_sort_order _ARG((String val)); void free_1_record _ARG((Record rec)); void free_record _ARG((Record rec)); void provide_to_record _ARG((Record rec,String s,String t)); void push_to_record _ARG((Record rec,String s,String t)); void sort_record _ARG((Record rec)); /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: copy_record() ** Purpose: Copy a record and return a new instance. ** If no memory is left then an error is raised and the ** program is terminated. ** Arguments: ** rec The record to copy. ** Returns: The new copy of |rec|. **___________________________________________________ */ Record copy_record(rec) /* */ register Record rec; /* */ { register Record new; /* */ register String *new_heap, /* */ *old_heap; /* */ register int i; /* */ /* */ if ( (new=(Record)malloc(sizeof(SRecord))) == 0L/* */ || (new_heap=(String*)malloc(sizeof(String)*(size_t)RecordFree(rec)))/* */ == 0L ) /* */ { OUT_OF_MEMORY("Record"); } /* */ RecordSortkey(new) = sym_empty; /* */ RecordOldKey(new) = RecordOldKey(rec); /* */ NextRecord(new) = RecordNULL; /* */ PrevRecord(new) = RecordNULL; /* */ RecordType(new) = RecordType(rec); /* */ RecordFree(new) = RecordFree(rec); /* */ RecordComment(new) = RecordComment(rec); /* */ RecordSource(new) = RecordSource(rec); /* */ RecordHeap(new) = new_heap; /* */ RecordFlags(new) = RecordFlags(rec); /* */ for (i = 0, old_heap = RecordHeap(rec); /* */ i < RecordFree(new); /* */ ++i) /* */ { *(new_heap++) = *(old_heap++); } /* */ return (new); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: new_record() ** Purpose: Create a new record and return it. ** If no memory is left then an error is raised and the ** program is terminated. ** Arguments: ** token The token type of the record. ** size The initial heap size. ** Returns: The new record. **___________________________________________________ */ Record new_record(token,size) /* */ int token; /* */ int size; /* */ { register Record new; /* */ register String *new_heap; /* */ register int i; /* */ /* */ if ( size < 1 ) size = 1; /* */ if ( (new=(Record)malloc(sizeof(SRecord))) == 0L/* */ || (new_heap=(String*)malloc(sizeof(String)*(size_t)(size)))/* */ == 0L ) /* */ { OUT_OF_MEMORY("Record"); } /* */ RecordSortkey(new) = sym_empty; /* */ RecordOldKey(new) = RecordSortkey(new); /* */ NextRecord(new) = RecordNULL; /* */ PrevRecord(new) = RecordNULL; /* */ RecordType(new) = token; /* */ RecordFree(new) = size; /* */ RecordComment(new) = sym_empty; /* */ RecordSource(new) = sym_empty; /* */ RecordFlags(new) = 0; /* */ RecordHeap(new) = new_heap; /* */ for (i = 0; i < RecordFree(new); ++i) /* */ { *(new_heap++) = StringNULL; } /* */ return (new); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_record() ** Purpose: Release a list of records. All records reachable through a ** previous/next chain are deallocated. ** Arguments: ** rec Arbitrary Record in the chain. ** Returns: nothing **___________________________________________________ */ void free_record(rec) /* */ Record rec; /* */ { Record r; /* */ /* */ if ( rec == RecordNULL ) return; /* */ /* */ while ( PrevRecord(rec) != RecordNULL ) /* rewind */ { rec = PrevRecord(rec); } /* */ /* */ while ( rec != RecordNULL ) /* */ { r = rec; /* */ rec = NextRecord(rec); /* */ free_1_record(r); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_1_record() ** Purpose: Free the memory occupied by a single record. ** This does not ensure that there is no dangling pointer to ** the record. Thus beware! ** Arguments: ** rec record to free ** Returns: nothing **___________________________________________________ */ void free_1_record(rec) /* */ Record rec; /* */ { int i; /* */ /* */ if ( rec != RecordNULL ) /* */ { /* */ ReleaseSymbol(RecordSortkey(rec)); /* */ ReleaseSymbol(RecordOldKey(rec)); /* */ ReleaseSymbol(RecordComment(rec)); /* */ ReleaseSymbol(RecordSource(rec)); /* */ if ( RecordHeap(rec) != NULL ) /* */ { /* */ for (i = 0; i < RecordFree(rec); i++ ) /* */ { ReleaseSymbol(RecordHeap(rec)[i]); } /* */ free(RecordHeap(rec)); /* */ } /* */ free(rec); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: unlink_record() ** Purpose: Remove a record from a chain and free its memory. The ** chain is modified such that the freed Record is not ** referenced any more. A neighbor in the chain of the ** given record is returned or |NULL| if there is none. ** Arguments: ** rec Record to free. ** Returns: nothing **___________________________________________________ */ Record unlink_record(rec) /* */ Record rec; /* */ { Record r; /* */ /* */ if ( NextRecord(rec) ) /* */ { PrevRecord(NextRecord(rec)) = PrevRecord(rec); /* */ if (PrevRecord(rec)) /* */ { NextRecord(PrevRecord(rec)) = NextRecord(rec);/* */ } /* */ r = NextRecord(rec); /* */ } /* */ else if (PrevRecord(rec)) /* */ { NextRecord(PrevRecord(rec)) = NextRecord(rec); /* */ r = PrevRecord(rec); /* */ } /* */ else /* */ { r = RecordNULL; /* */ } /* */ free_1_record(rec); /* */ return r; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: record_gc() ** Purpose: Garbage collecting a record list. The entries marked ** as deleted are unlinked and the memory is freed. Any ** pointer to such a deleted entry becomes invalid. ** ** Be careful when using this function! ** Arguments: ** rec Pointer to any entry in the chain. ** Returns: Pointer to some entry in the cleared chain or ** |RecordNULL| if none is left. **___________________________________________________ */ Record record_gc(rec) /* */ Record rec; /* */ { Record ret = RecordNULL; /* */ /* */ if ( rec == RecordNULL ) return rec; /* */ /* */ while ( PrevRecord(rec) != RecordNULL ) /* Rewind */ { rec = PrevRecord(rec); } /* */ /* */ while ( rec != RecordNULL ) /* */ { /* */ if ( RecordIsDELETED(rec) ) /* */ { rec = unlink_record(rec); /* */ } /* */ else /* */ { ret = rec; /* */ rec = NextRecord(rec); /* */ } /* */ } /* */ /* */ return ret; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: push_to_record() ** Purpose: Put an equation s=t onto the heap of a record. ** If a field s is already there then the value is ** overwritten. The arguments are expected to be ** symbols. Thus it is not necessary to make private ** copies and it is possible to avoid expensive string ** comparisons. ** Arguments: ** s Left hand side of the equation. ** t Right hand side of the equation. ** Returns: nothing **___________________________________________________ */ void push_to_record(rec,s,t) /* */ register Record rec; /* */ register String s; /* */ register String t; /* */ { register int i; /* */ /* */ if ( s == sym_crossref ) { SetRecordXREF(rec); } /* */ /* */ for (i = 2; i < RecordFree(rec); i += 2 ) /* search the field */ { if ( RecordHeap(rec)[i] == s ) /* if found then */ { RecordHeap(rec)[i+1] = t; /* overwrite the value */ return; /* */ } /* */ } /* */ for (i = 2; i < RecordFree(rec); i += 2 ) /* search empty field */ { if ( RecordHeap(rec)[i] == StringNULL ) /* if found then */ { RecordHeap(rec)[i++] = s; /* add the new item */ RecordHeap(rec)[i] = t; /* */ return; /* */ } /* */ } /* */ i = RecordFree(rec); /* */ RecordFree(rec) += 2; /* */ if ( (RecordHeap(rec) /* enlarge the heap */ =(String*)realloc(RecordHeap(rec), /* */ RecordFree(rec)*sizeof(String)))/* */ == (String*)NULL ) /* */ { OUT_OF_MEMORY("heap"); } /* */ /* */ RecordHeap(rec)[i++] = s; /* */ RecordHeap(rec)[i] = t; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: provide_to_record() ** Purpose: Put an equation s=t onto the heap of a record if the key s ** is not defined already. ** If a field s is already there then the value is ** ignored. The arguments are expected to be ** symbols. Thus it is not necessary to make private ** copies and it is possible to avoid expensive string ** comparisons. ** Arguments: ** s Left hand side of the equation. ** t Right hand side of the equation. ** Returns: nothing **___________________________________________________ */ void provide_to_record(rec,s,t) /* */ register Record rec; /* */ register String s; /* */ register String t; /* */ { register int i; /* */ /* */ if ( s == sym_crossref ) { SetRecordXREF(rec); } /* */ /* */ for (i = 2; i < RecordFree(rec); i += 2 ) /* search the field */ { if ( RecordHeap(rec)[i] == s ) /* if found then */ { return; /* done */ } /* */ } /* */ for (i = 2; i < RecordFree(rec); i += 2 ) /* search empty field */ { if ( RecordHeap(rec)[i] == StringNULL ) /* if found then */ { RecordHeap(rec)[i++] = s; /* add the new item */ RecordHeap(rec)[i] = t; /* */ return; /* */ } /* */ } /* */ i = RecordFree(rec); /* */ RecordFree(rec) += 2; /* */ if ( (RecordHeap(rec) /* enlarge the heap */ =(String*)realloc(RecordHeap(rec), /* */ RecordFree(rec)*sizeof(String)))/* */ == (String*)NULL ) /* */ { OUT_OF_MEMORY("heap"); } /* */ /* */ RecordHeap(rec)[i++] = s; /* */ RecordHeap(rec)[i] = t; /* */ } /*------------------------*/ /*****************************************************************************/ /*** ***/ /*****************************************************************************/ #include #include #include /*----------------------------------------------------------------------------- ** Function: new_wordlist() ** Purpose: Allocate a WordList and fill its slots. ** Arguments: ** s Initial string to fill in the WordList structure ** Returns: **___________________________________________________ */ WordList new_wordlist(s) /* */ String s; /* */ { register WordList wl; /* */ if ( (wl=(WordList)malloc(sizeof(SWordList))) == WordNULL )/* */ { OUT_OF_MEMORY("WordList"); } /* */ ThisWord(wl) = s; /* */ NextWord(wl) = WordNULL; /* */ return wl; /* */ } /*------------------------*/ typedef struct oRDERLIST /* */ { int ol_type; /* */ WordList ol_val; /* */ struct oRDERLIST *ol_next; /* */ } SOrderList, *OrderList; /* */ #define OrderType(OL) ((OL)->ol_type) #define OrderVal(OL) ((OL)->ol_val) #define NextOrder(OL) ((OL)->ol_next) #define OrderNULL ((OrderList)0) static OrderList order = OrderNULL; /* */ /*----------------------------------------------------------------------------- ** Function: add_sort_order() ** Purpose: Insert the sort order into the order list. ** ** ** Arguments: ** val string resource of the order. ** Returns: nothing **___________________________________________________ */ void add_sort_order(val) /* */ String val; /* */ { String s; /* */ int type; /* */ OrderList ol; /* */ WordList *wlp = NULL; /* */ WordList wl, wl_next; /* */ /* */ (void)SParseSkip(&val); /* */ if ( *val == '*' ) /* */ { s = StringNULL; /* */ type = BIB_NOOP; /* */ val++; /* */ } /* */ else if ( (s=SParseSymbol(&val)) == StringNULL ) /* */ { return; } /* */ else if ( (type=find_entry_type(s)) == BIB_NOOP )/* */ { Err("Undefined entry type for sort order"); /* */ return; /* */ } /* */ /* */ for (ol = order; /* */ ol != OrderNULL && OrderType(ol) != type; /* */ ol = NextOrder(ol)) {} /* */ /* */ if ( ol ) /* */ { wlp = &OrderVal(ol); /* */ } /* */ else if ( (ol=(OrderList)malloc(sizeof(SOrderList))) == OrderNULL )/* */ { OUT_OF_MEMORY("OrderList"); } /* */ else /* */ { OrderType(ol) = type; /* */ OrderVal(ol) = WordNULL; /* */ NextOrder(ol) = order; /* */ order = ol; /* */ wlp = &OrderVal(ol); /* */ } /* */ /* */ (void)SParseSkip(&val); /* */ /* */ while ( *val ) /* */ { if ( (s=SParseSymbol(&val)) != NULL ) /* */ { if ( *wlp ) { ThisWord(*wlp) = s; } /* */ else { *wlp = new_wordlist(s); } /* */ wlp = &NextWord(*wlp); /* */ } /* */ else break; /* */ SParseSkip(&val); /* */ } /* */ /* */ wl = *wlp; /* */ *wlp = WordNULL; /* */ while ( wl ) /* Free remaining word */ { wl_next = NextWord(wl); /* nodes at the end. */ free((char*)wl); /* */ wl = wl_next; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sort_record() ** Purpose: The heap is reordered according to the sorting order ** determined by the record type. ** For this purpose a copy of the original record is made and the ** original record is overwritten. The copy is released at the ** end. ** Memory management is easy since all strings are in fact ** symbols, i.e. they must not be freed and comparison is done ** by pointer comparison. ** Arguments: ** rec Record to sort ** Returns: nothing **___________________________________________________ */ void sort_record(rec) /* */ register Record rec; /* */ { Record r; /* Temp. record */ OrderList ol; /* */ int i, ptr; /* */ int type = RecordType(rec); /* */ WordList wl; /* */ /* */ for (ol = order; /* Search for an order */ ol && OrderType(ol) != type; /* for this type of */ ol = NextOrder(ol) ) {} /* record first. */ if ( ol == OrderNULL ) /* If none was found then */ { for (ol = order; /* Search for an order */ ol && OrderType(ol) != BIB_NOOP; /* applicable for all */ ol = NextOrder(ol) ) {} /* record types. */ if ( ol == OrderNULL ) return; /* No order then return. */ } /* */ /* */ if ( (wl=OrderVal(ol)) == WordNULL ) return; /* Empty order found. Done*/ /* */ r = copy_record(rec); /* */ ptr = 2; /* Heap pointer for rec */ /* */ while ( wl ) /* For all words */ { for ( i = 2; i < RecordFree(r); i += 2 ) /* Find the word on the */ { if ( RecordHeap(r)[i] == ThisWord(wl) ) /* heap and */ { RecordHeap(rec)[ptr++] = RecordHeap(r)[i]; /* transfer it into the */ RecordHeap(rec)[ptr++] = RecordHeap(r)[i+1];/* original record. */ RecordHeap(r)[i] = NULL; /* Delete the copy. */ i = RecordFree(r); /* */ } /* */ } /* */ wl = NextWord(wl); /* Look at next word. */ } /* */ for ( i = 2; i < RecordFree(r); i += 2 ) /* Transfer all remaining */ { if ( RecordHeap(r)[i] ) /* elements of the heap */ { RecordHeap(rec)[ptr++] = RecordHeap(r)[i]; /* which are not */ RecordHeap(rec)[ptr++] = RecordHeap(r)[i+1]; /* deleted. */ } /* */ } /* */ while ( ptr < RecordFree(r) ) /* Clear the remaining */ { RecordHeap(rec)[ptr++] = NULL; /* elements of the heap. */ } /* */ /* */ free((char*)RecordHeap(r)); /* Free the temp. record. */ free((char*)r); /* */ } /*------------------------*/ BibTool/rewrite.c0000644000175100017510000014007312646457572012704 0ustar genegene/*** rewrite.c **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #ifdef REGEX #include #endif typedef struct rULE { String rr_field; String rr_goal; String rr_value; String rr_frame; int rr_flag; struct rULE *rr_next; #ifdef REGEX struct re_pattern_buffer rr_pat_buff; #endif } SRule, *Rule; #define RuleNULL (Rule)0 #define RuleField(X) ((X)->rr_field) #define RuleGoal(X) ((X)->rr_goal) #define RuleValue(X) ((X)->rr_value) #define RulePattern(X) ((X)->rr_pat_buff) #define RuleFrame(X) ((X)->rr_frame) #define NextRule(X) ((X)->rr_next) #define RuleFlag(X) ((X)->rr_flag) #define RULE_NONE 0x00 #define RULE_ADD 0x01 #define RULE_REGEXP 0x02 #define RULE_NOT 0x04 #define RULE_RENAME 0x08 #define RULE_DELETE 0x016 /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int is_selected _ARG((DB db,Record rec)); /* */ int set_regex_syntax _ARG((char* name)); /* */ static Rule new_rule _ARG((String field,String value,String pattern,String frame,int flags,int casep)); static String check_regex _ARG((String field,String value,Rule rule,DB db,Record rec)); static String repl_regex _ARG((String field,String value,Rule rule,DB db,Record rec)); static int s_match _ARG((String p,String s)); /* */ static int s_search _ARG((String pattern,String s));/* */ static void add_rule _ARG((String s,Rule *rp,Rule *rp_end,int flags,int casep));/**/ #ifdef UNUSED static void free_rule _ARG((Rule rule)); /* */ #endif static void init_s_search _ARG((String ignored));/* */ static void rewrite_1 _ARG((String frame,StringBuffer *sb,String match,DB db,Record rec));/**/ void add_check_rule _ARG((String s)); /* */ void add_extract _ARG((String s,int regexp,int notp));/* */ void add_field _ARG((String spec)); /* */ void add_rewrite_rule _ARG((String s)); /* */ void clear_addlist _ARG((void)); /* */ void remove_field _ARG((String field,Record rec));/* */ void rename_field _ARG((String spec)); /* */ void rewrite_record _ARG((DB db,Record rec)); /* */ void save_regex _ARG((String s)); /* */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*****************************************************************************/ /*** Field Add/Delete Section ***/ /*****************************************************************************/ static Macro addlist = MacroNULL; /*----------------------------------------------------------------------------- ** Function: clear_addlist() ** Purpose: Reset the addlist to the empty list. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void clear_addlist() /* */ { /* */ free_macro(addlist); /* */ addlist = MacroNULL; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: add_field() ** Purpose: Save a token and value for addition. ** Arguments: ** spec A string of the form ** token=value ** Returns: nothing **___________________________________________________ */ void add_field(spec) /* */ String spec; /* */ { register String field, value; /* */ /* */ (void)sp_open(spec); /* */ if ( (field = SParseSymbol(&spec)) == StringNULL )/* */ return; /* */ (void)SParseSkip(&spec); /* */ if ( (value=SParseValue(&spec)) == StringNULL ) /* */ return; /* */ (void)SParseEOS(&spec); /* */ /* */ addlist = new_macro(field,value,addlist,0); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: remove_field() ** Purpose: Remove the given field from record. ** Arguments: ** field This is a symbol containing the name of the field to remove. ** rec Record in which the field should be removed. ** Returns: nothing **___________________________________________________ */ void remove_field(field, rec) /* */ register String field; /* */ Record rec; /* */ { register int i; /* */ /* */ for (i = 0; i < RecordFree(rec); i += 2 ) /* */ { if ( field == RecordHeap(rec)[i] ) /* compare symbols */ { RecordHeap(rec)[i] = StringNULL; } /* */ } /* */ /* */ while ( RecordFree(rec) > 0 && /* Adjust Heap Length */ RecordHeap(rec)[RecordFree(rec) - 2] == NULL )/* */ { RecordFree(rec) -= 2; /* */ } /* */ } /*------------------------*/ /*****************************************************************************/ /*** Rule Section ***/ /*****************************************************************************/ #ifdef REGEX static struct re_registers reg; /* */ #endif /*----------------------------------------------------------------------------- ** Function: new_rule() ** Purpose: Allocate a new Rule and fill some slots. ** Arguments: ** field The field to apply this rule to, or |NULL| for each field. ** value the value ** pattern the rule goal ** frame the rule frame ** flags The ored flag values ** casep Boolean; indicating case sensitive comparison. ** Returns: A pointer to the allocated structure or |NULL| upon failure. **___________________________________________________ */ static Rule new_rule(field, value, pattern, frame, flags, casep)/* */ String field; /* */ String value; /* */ String pattern; /* */ String frame; /* */ int flags; /* */ int casep; /* */ { register Rule rule; /* */ static int init = 1; /* */ /* */ #ifdef REGEX if ( init ) /* */ { init = 0; /* */ reg.num_regs = 32; /* */ reg.start = (regoff_t*)calloc(32,sizeof(regoff_t));/* */ reg.end = (regoff_t*)calloc(32,sizeof(regoff_t));/* */ if ( reg.start == NULL || reg.end == NULL ) /* */ { OUT_OF_MEMORY("rewrite rule"); } /* */ } /* */ #endif /* */ if ( (rule=(Rule)malloc(sizeof(SRule))) == RuleNULL )/* */ { OUT_OF_MEMORY("rewrite rule"); } /* */ /* */ RuleField(rule) = field; /* */ RuleValue(rule) = value; /* */ RuleFrame(rule) = frame; /* */ RuleFlag(rule) = flags; /* */ NextRule(rule) = RuleNULL; /* */ RuleGoal(rule) = pattern; /* */ /* */ #ifdef REGEX if ( pattern && *pattern && (flags&RULE_REGEXP) )/* */ { char *msg; /* */ if ( (RulePattern(rule).buffer = (String)malloc(16)) == NULL )/* */ { OUT_OF_MEMORY("pattern"); } /* */ RulePattern(rule).allocated = 16; /* */ RulePattern(rule).syntax = RE_SYNTAX_EMACS; /* */ RulePattern(rule).fastmap = NULL; /* */ RulePattern(rule).regs_allocated = REGS_FIXED; /* */ RulePattern(rule).translate = (casep /* */ ? (char*)trans_lower/* */ : NULL); /* */ /* */ msg = (char*)re_compile_pattern((char*)pattern,/* */ strlen((char*)pattern),/* */ &RulePattern(rule) );/* */ if ( msg ) { /* */ Err(msg); /* */ free(rule); /* */ return NULL; /* */ } /* */ } /* */ else /* */ { RuleFlag(rule) = (flags & ~RULE_REGEXP); /* */ } /* */ #endif DebugPrint2("pattern = ",pattern); /* */ DebugPrint2("frame = ",frame); /* */ DebugPrintF1("+++ BibTool: flags ="); /* */ DebugPrintF1(flags & RULE_NOT ? " NOT" : ""); /* */ DebugPrintF1(flags & RULE_ADD ? " ADD" : ""); /* */ DebugPrintF1(flags & RULE_RENAME ? " RENAME" : "");/* */ DebugPrintF1(flags & RULE_REGEXP ? " REGEXP" : "");/* */ DebugPrintF1("\n"); /* */ DebugPrintF2("+++ BibTool: New rule = %lx\n", /* */ (long)rule); /* */ /* */ return rule; /* */ } /*------------------------*/ #ifdef UNUSED /*----------------------------------------------------------------------------- ** Function: free_rule() ** Purpose: Free a list of rules. ** ** ** Arguments: ** rule First rule in the list. ** Returns: nothing **___________________________________________________ */ static void free_rule(rule) /* */ Rule rule; /* */ { Rule next; /* */ /* */ while ( rule ) /* */ { next = NextRule(rule); /* */ #ifdef REGEX free(RulePattern(rule).buffer); /* */ #endif free(rule); /* */ rule = next; /* */ } /* */ } /*------------------------*/ #endif /*----------------------------------------------------------------------------- ** Function: add_rule() ** Purpose: Generic addition of a rule to a list of rules. ** Arguments: ** s ** rp ** rp_end ** flags ** casep ** Returns: nothing **___________________________________________________ */ static void add_rule(s,rp,rp_end,flags,casep) /* */ String s; /* */ Rule *rp; /* */ Rule *rp_end; /* */ int flags; /* */ int casep; /* */ { String field; /* */ String pattern; /* */ String frame; /* */ Rule rule; /* */ int sp; /* */ int stackp; /* stack pointer for the */ static String *stack; /* local stack of fields */ static int stacksize = 0; /* */ /* */ if ( stacksize == 0 ) /* */ { stacksize++; /* */ if ((stack=(String*)malloc(sizeof(String)))==(String*)NULL)/* */ { OUT_OF_MEMORY("rule stack"); } /* */ } /* */ stackp = 0; /* */ /* */ DebugPrint2("Adding rule: Parsing from: ", s); /* */ (void)sp_open(s); /* */ (void)SParseSkip(&s); /* */ /* */ while (*s && *s != '"') /* */ { /* */ DebugPrint2("\tlooking for symbol in: ", s); /* */ field = SParseSymbol(&s); /* */ DebugPrint2("\tok ",s); /* */ if (field == NULL) /* */ { DebugPrint2("\tno symbol found in: ", s); /* */ return; /* */ } /* */ DebugPrint2("field = ",field); /* */ (void)SParseSkip(&s); /* */ /* */ if (stackp >= stacksize) /* */ { stacksize += 8; /* */ if ( (stack=(String*)realloc((char*)stack, /* */ stacksize*sizeof(char*)))==NULL)/* */ { OUT_OF_MEMORY("rule stack"); } /* */ } /* */ stack[stackp++] = field; /* */ } /* */ /* */ if ( *s == '\0' ) /* */ { pattern = symbol((String)"."); } /* */ else if ( (pattern=SParseUnquotedString(&s)) == NULL )/* */ { DebugPrintF1("No pattern found"); /* */ return; /* */ } /* */ /* */ (void)SParseSkip(&s); /* */ /* */ if ( *s == '\0' ) /* */ { frame = StringNULL; } /* */ else if ( (frame=SParseUnquotedString(&s)) == NULL )/* */ { return; } /* */ else /* */ { (void)SParseEOS(&s); } /* */ /* */ if (stackp == 0) /* No field specified. */ { rule = new_rule(StringNULL, /* */ StringNULL, /* */ pattern, /* */ frame, /* */ flags, /* */ casep); /* */ if ( *rp == RuleNULL ) /* */ { *rp = *rp_end = rule; } /* */ else /* */ { NextRule(*rp_end) = rule; *rp_end = rule;} /* */ return; /* */ } /* */ /* */ for (sp = 0; sp < stackp; sp++) /* */ { rule = new_rule(stack[sp], /* */ StringNULL, /* */ pattern, /* */ frame, /* */ flags, /* */ casep); /* */ if ( *rp == RuleNULL ) /* */ { *rp = *rp_end = rule; } /* */ else /* */ { NextRule(*rp_end) = rule; *rp_end = rule;} /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rewrite_1() ** Purpose: ** ** ** Arguments: ** frame ** sb ** match ** rec ** Returns: nothing **___________________________________________________ */ static void rewrite_1(frame,sb,match,db,rec) /* */ String frame; /* */ StringBuffer *sb; /* */ String match; /* */ DB db; /* */ Record rec; /* */ { /* */ for ( ; *frame; frame++ ) /* */ { if ( *frame == '%' ) /* */ { frame = fmt_expand(sb, frame, db, rec); } /* */ else if ( *frame != '\\' ) /* Transfer normal */ { (void)sbputchar(*frame,sb); } /* characters. */ else /* */ { /* */ switch ( *++frame ) /* */ { case '1': case '2': case '3': /* */ case '4': case '5': case '6': /* */ case '7': case '8': case '9': /* */ #ifdef REGEX { int i = *frame - '0'; /* Look for register no */ int e = reg.end[i]; /* get end of match */ /* */ for ( i=reg.start[i]; i= 0 ); /* */ #else return TRUE; /* */ #endif } /*------------------------*/ #endif /*----------------------------------------------------------------------------- ** Function: repl_regex() ** Purpose: ** ** ** Arguments: ** field ** value ** rule ** rec ** Returns: **___________________________________________________ */ static String repl_regex(field, value, rule, db, rec)/* */ String field; /* */ String value; /* */ Rule rule; /* */ DB db; /* */ Record rec; /* */ { /* */ #ifdef REGEX char c; /* */ int len; /* */ StringBuffer *sp; /* intermediate pointer */ int once_more; /* */ int limit; /* depth counter to break */ /* out of infinite loops */ static StringBuffer *s1 = NULL; /* */ static StringBuffer *s2 = NULL; /* */ /* */ if (rule == RuleNULL) return value; /* */ /* */ if (s1 == NULL) { s1 = sbopen(); s2 = sbopen(); }/* */ else { sbrewind(s1); sbrewind(s2); }/* */ /* */ (void)sbputs((char*)value, s1); /* */ value = (String)sbflush(s1); /* */ len = strlen((char*)value); /* */ limit = rsc_rewrite_limit; /* */ once_more = TRUE; /* */ /* */ while ( once_more ) /* */ { /* */ once_more = FALSE; /* */ while (rule != RuleNULL) /* */ { /* */ #ifdef DEBUG printf("+++ BibTool: repl_regex rule:0x%lx flags:0x%x field:%s <> %s\n", (long)rule, RuleFlag(rule), RuleField(rule), field); #endif if ((RuleFlag(rule) & RULE_RENAME) != 0) /* */ { /* */ if (RuleField(rule) == field && /* */ selector_hits(rule, db, rec)) /* */ { int i; /* */ String *hp; /* */ for (i = RecordFree(rec), hp = RecordHeap(rec);/* */ i > 0; /* */ i -= 2, hp += 2) /* */ { /* */ if (*hp == field) /* */ { field = *hp = RuleValue(rule); /* */ break; /* */ } /* */ } /* */ } /* */ rule = NextRule(rule); /* */ limit = rsc_rewrite_limit; /* */ } /* */ else if ( ( RuleField(rule) == NULL /* */ || RuleField(rule) == field ) && /* */ (RuleFlag(rule) & RULE_ADD) == 0 && /* */ re_search(&RulePattern(rule), /* */ (char*)value, /* */ len, /* */ 0, /* */ len-1, /* */ ®) >= 0 ) /* */ { /* */ if ( 0 > --limit ) /* */ { ErrPrint("\n*** BibTool WARNING: Rewrite limit exceeded for field "); ErrPrint((char*)field); /* */ ErrPrint("\n\t\t in record "); /* */ ErrPrint((*RecordHeap(rec)?(char*)*RecordHeap(rec):""));/* */ ErrPrint("\n"); /* */ once_more = FALSE; /* */ break; /* */ } /* */ if ( RuleFrame(rule) == StringNULL ) /* */ { return StringNULL; } /* */ /* */ if ( reg.start[0] > 0 ) /* */ { c = value[reg.start[0]]; /* Push initial segment */ value[reg.start[0]] = '\0'; /* */ (void)sbputs((char*)value, s2); /* */ value[reg.start[0]] = c; /* */ } /* */ /* */ rewrite_1(RuleFrame(rule),s2,value,db,rec);/* */ /* */ (void)sbputs((char*)(value+reg.end[0]),s2);/* Transfer the end. */ /* */ value = (String)sbflush(s2); /* update the value */ len = strlen((char*)value); /* and its length */ sp = s1; s1 = s2; s2 = sp; /* rotate the two string */ sbrewind(s2); /* buffers and reset */ /* the destination. */ once_more = TRUE; /* */ } /* */ else /* */ { rule = NextRule(rule); /* */ limit = rsc_rewrite_limit; /* */ } /* */ } /* */ } /* */ #endif return value; /* return the result. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: check_regex() ** Purpose: ** ** ** Arguments: ** field ** value ** rule ** rec ** Returns: **___________________________________________________ */ static String check_regex(field, value, rule, db, rec)/* */ String field; /* */ String value; /* */ Rule rule; /* */ DB db; /* */ Record rec; /* */ { /* */ #ifdef REGEX int len; /* */ static StringBuffer *s2 = 0L; /* */ /* */ if ( rule == RuleNULL ) return value; /* */ /* */ if ( s2 == NULL ) { s2 = sbopen(); } /* */ else { sbrewind(s2); } /* */ /* */ for ( len = strlen((char*)value); /* Loop through all rules */ rule != RuleNULL; /* */ rule = NextRule(rule) ) /* */ { /* */ if ( ( RuleField(rule) == NULL /* */ || RuleField(rule) == field ) /* */ && /* */ ( (RuleFlag(rule)&RULE_REGEXP) == 0 /* */ || re_search(&RulePattern(rule), /* */ (char*)value, /* */ len,0,len-1,®) >=0 /* */ ) /* */ ) /* */ { if ( RuleFrame(rule) == StringNULL ) /* */ { return StringNULL; } /* */ rewrite_1(RuleFrame(rule),s2,value,db,rec); /* */ value = (String)sbflush(s2); /* update the value */ return value; /* */ } /* */ } /* */ #endif return StringNULL; /* return the result. */ } /*------------------------*/ /*---------------------------------------------------------------------------*/ static Rule r_rule = RuleNULL; static Rule r_rule_end = RuleNULL; /*----------------------------------------------------------------------------- ** Function: rename_field() ** Type: void ** Purpose: ** ** Arguments: ** s ** Returns: nothing **___________________________________________________ */ void rename_field(spec) /* */ String spec; /* */ { /* */ String from; /* */ String to; /* */ String field = StringNULL; /* */ String pattern = StringNULL; /* */ /* */ (void)sp_open(spec); /* */ (void)SParseSkip(&spec); /* */ if ( (from = SParseSymbol(&spec)) == StringNULL )/* */ return; /* */ (void)SParseSkip(&spec); /* */ if ( (to = SParseSymbol(&spec)) == StringNULL ) /* */ return; /* */ /* */ if (sp_expect(&spec, (String)"if")) /* */ { if ( (field = SParseOptionalSymbol(&spec)) != StringNULL )/* */ { (void)SParseSkip(&spec); /* */ if ( (pattern = SParseValue(&spec)) == StringNULL )/* */ return; /* */ } /* */ } /* */ if (SParseEOS(&spec) != StringNULL ) return; /* */ /* */ Rule rule = new_rule(from, /* */ to, /* */ pattern, /* */ field, /* */ RULE_RENAME | RULE_REGEXP, /* */ rsc_case_rewrite); /* */ if (r_rule == RuleNULL) /* */ { r_rule = r_rule_end = rule; /* */ } /* */ else /* */ { NextRule(r_rule_end) = rule; /* */ r_rule_end = rule; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: add_rewrite_rule() ** Purpose: Save a rewrite rule for later use. ** The main task is performed by |add_rule()|. ** Arguments: ** s Rule to save. ** Returns: nothing **___________________________________________________ */ void add_rewrite_rule(s) /* */ String s; /* */ { /* */ DebugPrintF1("add rewrite rule\n"); /* */ /* */ add_rule(s, /* */ &r_rule, /* */ &r_rule_end, /* */ RULE_REGEXP, /* */ rsc_case_rewrite); /* */ } /*------------------------*/ static Rule c_rule = RuleNULL; static Rule c_rule_end = RuleNULL; /*----------------------------------------------------------------------------- ** Function: add_check_rule() ** Purpose: Save a check rule for later use. ** Arguments: ** s Rule to save. ** Returns: nothing **___________________________________________________ */ void add_check_rule(s) /* */ String s; /* */ { /* */ DebugPrintF1("add check rule\n"); /* */ add_rule(s, /* */ &c_rule, /* */ &c_rule_end, /* */ RULE_REGEXP, /* */ rsc_case_check); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rewrite_record() ** Purpose: Apply deletions, checks, additions, and rewriting steps ** in this order. ** Arguments: ** rec Actual record to apply things to. ** db The database record is belonging to. ** Returns: nothing **___________________________________________________ */ void rewrite_record(db, rec) /* */ DB db; /* */ register Record rec; /* */ { register int i; /* */ register String *hp; /* heap pointer */ register Macro mac; /* */ String cp; /* */ static StringBuffer *sb = NULL; /* */ /* */ if (sb == NULL) sb = sbopen(); /* */ /* */ if (c_rule != RuleNULL) /* */ { /* */ for (i = RecordFree(rec), hp = RecordHeap(rec);/* */ i > 0; /* */ i -= 2, hp +=2) /* */ { /* */ if ( *hp /* */ && *(hp+1) /* */ && StringNULL != /* */ (cp=check_regex(*hp,*(hp+1),c_rule,db,rec))/* */ ) /* */ { Err(cp); } /* */ } /* */ } /* */ /* */ if (r_rule != RuleNULL) /* */ { /* */ for (i = RecordFree(rec), hp = RecordHeap(rec);/* */ i > 0; /* */ i -= 2, hp += 2) /* */ { /* */ if (*hp && *(hp+1)) /* */ { /* */ cp = repl_regex(*hp,*(hp+1),r_rule,db,rec);/* */ if ( cp == StringNULL ) /* */ { *hp = *(hp+1) = StringNULL; } /* */ else if ( cp != *(hp+1) ) /* */ { *(hp+1) = symbol(cp); } /* */ } /* */ } /* */ } /* */ /* */ for (mac = addlist; /* Add all items in the */ mac; /* add list */ mac = NextMacro(mac) ) /* */ { cp = MacroValue(mac); /* */ sbrewind(sb); /* */ sbputc('{',sb); /* */ while ( *cp ) /* */ { /* */ if ( *cp == '%' ) /* */ { if ( *(cp+1) == '%' ) /* */ { sbputc(*cp,sb); cp+=2; } /* */ else { cp = fmt_expand(sb,cp,db,rec); } /* */ } /* */ else { sbputc(*cp,sb); cp++; } /* */ } /* */ sbputc('}', sb); /* */ push_to_record(rec, /* */ MacroName(mac), /* */ sym_add((String)sbflush(sb),1));/* */ } /* */ } /*------------------------*/ /*---------------------------------------------------------------------------*/ static Rule x_rule = RuleNULL; static Rule x_rule_end = RuleNULL; /*----------------------------------------------------------------------------- ** Function: add_extract() ** Purpose: Save an extraction rule for later use. The argument is ** interpreted as regular expression to be matched ** against the field value. ** ** The value of |rsc_case_select| at the invocation of ** this function determines whether the matching is ** performed case sensitive or not. ** Arguments: ** s Rule to save. ** regexp Boolean value indicating whether regular expressions ** should be used. If not set then plain string matching ** is performed. ** notp Boolean value indicating whether the result should be ** negated. ** Returns: nothing **___________________________________________________ */ void add_extract(s,regexp,notp) /* */ String s; /* */ int regexp; /* */ int notp; /* */ { /* */ add_rule(s, /* The main task is */ &x_rule, /* performed by */ &x_rule_end, /* |add_rule()|. */ (regexp?RULE_REGEXP:RULE_NONE) | /* */ (notp ?RULE_NOT :RULE_NONE) , /* */ !rsc_case_select); /* */ rsc_select = TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: save_regex() ** Purpose: Save an extraction rule for later use. ** Only the regular expression of the rule is given as argument. ** The fields are taken from the resource select.fields. ** Arguments: ** s Regular expression to search for. ** Returns: nothing **___________________________________________________ */ void save_regex(s) /* */ String s; /* */ { String t = malloc( (size_t)strlen((char*)s) /* */ + (size_t)strlen((char*)rsc_sel_fields)/* */ + 4 ); /* */ if ( t == NULL ) { OUT_OF_MEMORY("string"); } /* */ /* */ (void)strcpy((char*)t, (char*)rsc_sel_fields); /* */ (void)strcat((char*)t, " \""); /* */ (void)strcat((char*)t, (char*)s); /* */ (void)strcat((char*)t, "\""); /* */ /* */ add_rule(t, /* */ &x_rule, /* */ &x_rule_end, /* */ RULE_REGEXP, /* */ !rsc_case_select); /* */ /* */ free((char*)t); /* */ rsc_select = TRUE; /* */ } /*------------------------*/ static char s_class[256]; /* */ static String s_ignored = (String)NULL; /* */ static int s_cased = -33; /* */ /*----------------------------------------------------------------------------- ** Function: init_s_search() ** Purpose: ** ** ** Arguments: ** ignored ** Returns: Nothing **___________________________________________________ */ static void init_s_search(ignored) /* */ String ignored; /* */ { int i; /* */ for (i = 0; i < 256; i++) s_class[i] = i; /* */ /* */ if (!rsc_case_select) /* */ { /* */ s_class['a'] = 'A'; /* */ s_class['b'] = 'B'; /* */ s_class['c'] = 'C'; /* */ s_class['d'] = 'D'; /* */ s_class['e'] = 'E'; /* */ s_class['f'] = 'F'; /* */ s_class['g'] = 'G'; /* */ s_class['h'] = 'H'; /* */ s_class['i'] = 'I'; /* */ s_class['j'] = 'J'; /* */ s_class['k'] = 'K'; /* */ s_class['l'] = 'L'; /* */ s_class['m'] = 'M'; /* */ s_class['n'] = 'N'; /* */ s_class['o'] = 'O'; /* */ s_class['p'] = 'P'; /* */ s_class['q'] = 'Q'; /* */ s_class['r'] = 'R'; /* */ s_class['s'] = 'S'; /* */ s_class['t'] = 'T'; /* */ s_class['u'] = 'U'; /* */ s_class['v'] = 'V'; /* */ s_class['w'] = 'W'; /* */ s_class['x'] = 'X'; /* */ s_class['y'] = 'Y'; /* */ s_class['z'] = 'Z'; /* */ } /* */ while ( *ignored ) /* */ { s_class[(unsigned int)(*(ignored++))] = '\0'; }/* */ /* */ s_cased = rsc_case_select; /* */ s_ignored = symbol((String)rsc_sel_ignored); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: s_match() ** Purpose: ** ** ** Arguments: ** p ** s ** Returns: **___________________________________________________ */ static int s_match(p,s) /* */ String p; /* */ String s; /* */ { /* */ while ( *p && s_class[(unsigned int)*p] == '\0' ) p++;/* */ /* */ while ( *p ) /* */ { /* */ while ( *s && s_class[(unsigned int)*s] == '\0' ) s++;/* */ /* */ if ( s_class[(unsigned int)*s] != s_class[(unsigned int)*p] ) return FALSE; while ( *p && s_class[(unsigned int)*p] == '\0' ) p++;/* */ if (*s) s++; /* */ if (*p) p++; /* */ } /* */ return TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: s_search() ** Purpose: Match a pattern against all positions in a string. If ** a match is found then |TRUE| is returned. Otherwise ** |FALSE|. ** Arguments: ** pattern ** s ** Returns: **___________________________________________________ */ static int s_search(pattern,s) /* */ String pattern; /* */ String s; /* */ { /* */ if ( s_cased != rsc_case_select || /* */ strcmp((char*)s_ignored, /* */ (char*)rsc_sel_ignored) != 0 ) /* */ { init_s_search(rsc_sel_ignored); } /* */ /* */ for ( ; *s; s++ ) /* */ { if ( s_match(pattern,s) ) return TRUE; /* */ } /* */ return FALSE; /* */ } /*------------------------*/ #define ReturnIf(COND) \ if ( COND ) \ { if ( !(RuleFlag(rule) & RULE_NOT) ) return TRUE; } \ else \ { if ( (RuleFlag(rule) & RULE_NOT) ) return TRUE; } /*----------------------------------------------------------------------------- ** Function: is_selected() ** Purpose: Boolean function to decide whether a record should be ** considered. These selections are described by a set of ** regular expressions which are applied. If none are ** given then the match simply succeeds. ** Arguments: ** db Database containing the record. ** rec Record to look at. ** Returns: |TRUE| iff the record is seleced by a regexp or none is ** given. **___________________________________________________ */ int is_selected(db,rec) /* */ DB db; /* */ Record rec; /* */ { /* */ int len, i; /* */ String value; /* */ Rule rule; /* */ /* */ if ( (rule=x_rule) == RuleNULL || /* If no rule is given or */ !rsc_select /* no selection is */ ) /* requested then */ return TRUE; /* select all records. */ /* */ for ( ; /* Loop through all rules */ rule != RuleNULL; /* */ rule = NextRule(rule) ) /* */ { /* */ if ( RuleField(rule) == NULL ) /* If no field is given */ { /* then try all normal */ if ( RuleFlag(rule) & RULE_REGEXP ) /* */ { /* */ #ifdef REGEX if ( RecordHeap(rec)[0] ) /* */ { len = strlen((char*)(RecordHeap(rec)[0]));/* */ ReturnIf(re_search(&RulePattern(rule), /* */ (char*)RecordHeap(rec)[0],/* */ len, /* */ 0, /* */ len-1, /* */ ®) >= 0 ); /* */ } /* */ for (i = 2; i < RecordFree(rec); i += 2 ) /* */ { if ( RecordHeap(rec)[i] ) /* */ { len = strlen((char*)(RecordHeap(rec)[i+1]));/* */ ReturnIf(re_search(&RulePattern(rule), /* */ (char*)RecordHeap(rec)[i+1],/* */ len, /* */ 0, /* */ len-1, /* */ ®) >= 0 ); /* */ } /* */ } /* */ #endif } /* */ else /* */ { /* */ if ( RecordHeap(rec)[0] ) /* */ { ReturnIf(s_search(RuleGoal(rule), /* */ RecordHeap(rec)[0]) ); /* */ } /* */ for (i = 2; i < RecordFree(rec); i += 2 ) /* */ { if ( RecordHeap(rec)[i] ) /* */ { ReturnIf(s_search(RuleGoal(rule), /* */ RecordHeap(rec)[i+1]) );/* */ } /* */ } /* */ } /* */ } /* */ else if ( (value=get_field(db, /* */ rec, /* */ RuleField(rule))) /* */ != NULL ) /* */ { /* */ if ( RuleFlag(rule) & RULE_REGEXP ) /* */ { /* */ #ifdef REGEX len = strlen((char*)value); /* */ ReturnIf(re_search(&RulePattern(rule), /* */ (char *)value, /* */ len, /* */ 0, /* */ len-1, /* */ ®) >=0 ) /* */ #endif } /* */ else ReturnIf(s_search(RuleGoal(rule),value))/* */ } /* */ else if ( RuleFlag(rule) & RULE_NOT ) /* */ { return TRUE; /* */ } /* */ } /* */ return FALSE; /* return the result. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: set_regex_syntax() ** Type: int ** Purpose: experimental ** ** Arguments: ** name ** Returns: nothing **___________________________________________________ */ int set_regex_syntax(name) /* */ char* name; /* */ { /* */ #ifdef REGEX if ( strcmp(name,"emacs") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_EMACS); } /* */ else if ( strcmp(name,"awk") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_AWK); } /* */ else if ( strcmp(name,"grep") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_GREP); } /* */ else if ( strcmp(name,"egrep") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_EGREP); } /* */ else if ( strcmp(name,"posix_awk") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_POSIX_AWK); } /* */ else if ( strcmp(name,"posix_egrep") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_POSIX_EGREP); } /* */ else if ( strcmp(name,"ed") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_ED); } /* */ else if ( strcmp(name,"sed") == 0 ) /* */ { re_set_syntax(RE_SYNTAX_SED); } /* */ else /* */ { WARNING3("Unknown regexp syntax: ",name,"\n"); /* */ return 1; /* */ } /* */ #endif return 0; /* */ } /*------------------------*/ BibTool/rsc.c0000644000175100017510000003312612646457620012004 0ustar genegene/*** rsc.c ******************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions which deal with resources. ** Resources are commands to configure the behaviour of ** \BibTool. They can be read either from a file or from a ** string. ** ** The syntax of resources are modelled after the syntax rules ** for \BibTeX{} files. See the user's guide for details of the syntax. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #define RSC_INIT #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int load_rsc _ARG((String name)); /* */ int resource _ARG((String name)); /* */ int search_rsc _ARG((void)); /* */ int set_rsc _ARG((String name,String val)); /* */ int use_rsc _ARG((String s)); /* */ static int test_true _ARG((String s)); /* */ static void init_rsc _ARG((void)); /* */ void rsc_print _ARG((String s)); /* */ #define NoRscError(X) WARNING3("Resource file ",X," not found.") /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ extern void save_input_file _ARG((char *file)); /* main.c */ extern void save_macro_file _ARG((char * file)); /* main.c */ extern void save_output_file _ARG((char * file)); /* main.c */ #ifndef __STDC__ #ifndef HAVE_GETENV extern char * getenv _ARG((char* name)); /* */ #endif #endif /*---------------------------------------------------------------------------*/ #define RscNumeric(SYM,S,V,I) static String S = StringNULL; #define RscString(SYM,S,V,I) static String S = StringNULL; #define RscBoolean(SYM,S,V,I) static String S = StringNULL; #define RscByFct(SYM,S,FCT) static String S = StringNULL; #include /*----------------------------------------------------------------------------- ** Function: init_rsc() ** Purpose: This function performs resource initializations. It ** is necessary to call this function before the other ** functions in this module can be expected to work ** properly. Thus it is called at the beginning of the ** functions is question. ** Details: ** Initialize the key words. ** Tricky use of CPP. The header file resource.h is included ** for the second time. To avoid confusion in makedepend the ** hader file is only included if MAKEDPEND is not defined. ** The same trick can be found again later. ** Arguments: none ** Returns: nothing **___________________________________________________ */ static void init_rsc() /* */ { /* */ #define RscNumeric(SYM,S,V,I) S = symbol((String)SYM); #define RscString(SYM,S,V,I) S = symbol((String)SYM); #define RscBoolean(SYM,S,V,I) S = symbol((String)SYM); #define RscByFct(SYM,S,FCT) S = symbol((String)SYM); #ifndef MAKEDEPEND #include #endif } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: search_rsc() ** Purpose: Try to open the resource file at different places: ** \begin{itemize} ** \item In the place indicated by the environment variable ** |RSC_ENV_VAR|. This step is skipped if the macro ** |RSC_ENV_VAR| is not defined (at compile time of the ** module). ** \item In the home directory. The home directory is ** determined by an environment variable. The macro ** |HOME_ENV_VAR| contains the name of this environment ** variable. If this macro is not defined (at ** compile time of the module) then this step is skipped. ** \item In the usual place for resource files. ** \end{itemize} ** For each step |load_rsc()| is called until it ** succeeds. ** ** The files sought is determined by the macro ** |DefaultResourceFile| at compile time of the ** module. (see |bibtool.h|) ** Arguments: none ** Returns: |TRUE| iff the resource loading succeeds somewhere. **___________________________________________________ */ int search_rsc() /* */ { static String def = (String)DefaultResourceFile;/* */ register char *ap; /* */ register char *fn; /* */ int l; /* */ /* */ #ifdef RSC_ENV_VAR if ( (ap=getenv(RSC_ENV_VAR)) != NULL /* Try to get the name */ && load_rsc((String)ap) ) return TRUE; /* from the environment. */ #endif /* */ #ifdef HOME_ENV_VAR if ( (ap=getenv(HOME_ENV_VAR)) != NULL ) /* Try to get the resource*/ { l = strlen(ap) + /* */ strlen(DIR_SEP) + /* */ strlen((char*)def) + 1; /* file from the home */ if ( (fn=malloc(l)) != NULL ) /* directory */ { (void)strcpy(fn, ap); /* */ (void)strcat(fn, DIR_SEP); /* */ (void)strcat(fn, (char*)def); /* */ l = load_rsc((String)fn); /* */ free(fn); /* */ if ( l ) return TRUE; /* */ } /* */ } /* */ #endif /* if all fails then try */ return load_rsc(def); /* to use a default. */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: load_rsc() ** Purpose: This function tries to load a resource file. ** Details: ** Perform initialization if required. ** The main job is done by |read_rsc()|. This function is located ** in |parse.c| since it shares subroutines with the parser. ** Arguments: ** name The name of the resource file to read. ** Returns: |FALSE| iff the reading failed. **___________________________________________________ */ int load_rsc(name) /* */ register String name; /* */ { /* */ if ( r_v == NULL ) { init_rsc(); } /* */ return ( name != NULL ? read_rsc(name) : 0 ); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: resource() ** Type: int ** Purpose: ** ** Arguments: ** name ** Returns: **___________________________________________________ */ int resource(name) /* */ register String name; /* */ { /* */ int ret = load_rsc(name); /* */ if ( !ret ) { NoRscError(name); } /* */ return ret; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: test_true() ** Purpose: A boolean resource can be set to true in different ways: ** |true|, |t|, |yes|, |on|, |1| ** which represent ``true''. Each other value is ** interpreted as ``false''. ** The comparison is done case insensitive. ** Arguments: ** s String to check for the boolean value. ** Returns: |TRUE| iff the string represents true. **___________________________________________________ */ static int test_true(s) /* */ String s; /* */ { /* */ switch ( *s ) /* */ { case '1': return (s[1] == '\0'); /* */ case 'o': case 'O': /* */ return ((s[1] == 'n' || s[1] == 'N') && /* */ s[2] == '\0' ); /* */ case 'y': case 'Y': /* */ return ((s[1] == 'e' || s[1] == 'E') && /* */ (s[2] == 's' || s[2] == 'S') && /* */ s[3] == '\0' ); /* */ case 't': case 'T': /* */ return (s[1] == '\0' || /* */ ((s[1] == 'r' || s[1] == 'R') && /* */ (s[2] == 'u' || s[2] == 'U') && /* */ (s[3] == 'e' || s[3] == 'E') && /* */ s[4] == '\0')); /* */ } /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: use_rsc() ** Purpose: This function can be used to evaluate a single ** resource instruction. The argument is a string which ** is parsed to extract the resource command. ** ** This is an entry point for command line options which ** set resources. ** Arguments: ** s String containing a resource command. ** Returns: |FALSE| iff no error has occurred. **___________________________________________________ */ int use_rsc(s) /* */ String s; /* */ { register String name, /* */ value; /* */ /* */ (void)sp_open(s); /* */ if ( (name = SParseSymbol(&s)) == NULL ) return 1; /* */ /* */ (void)SParseSkip(&s); /* */ /* */ if ( (value = SParseValue(&s)) == NULL ) /* */ { ReleaseSymbol(name); /* */ return 1; /* */ } /* */ /* */ if ( r_v == NULL ) { init_rsc(); } /* */ /* */ return set_rsc(name,value); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: set_rsc() ** Purpose: Set the resource to a given value. Here the assignment ** is divided into two parts: the name and the value. ** Both arguments are assumed to be symbols. ** Arguments: ** name Name of the resource to set. ** val The new value of the resource. ** Returns: |FALSE| iff everything went right. **___________________________________________________ */ int set_rsc(name,val) /* */ String name; /* */ String val; /* */ { /* */ if ( rsc_verbose ) /* */ { VerbosePrint4("Resource ", /* */ (char*)name, /* */ " = ", /* */ (val==NULL?"*NULL*":(char*)val));/* */ } /* */ /* */ #define SETQ(V,T) V=T; ReleaseSymbol(name); #define RscNumeric(SYM,S,V,I) \ if( name==S ) { SETQ(V,atoi((char*)val)); ReleaseSymbol(val); return 0; } #define RscString(SYM,S,V,I) \ if( name==S ) { ReleaseSymbol(V); V = val; ReleaseSymbol(name); return 0; } #define RscBoolean(SYM,S,V,I) \ if( name==S ) { SETQ(V,test_true(val)); ReleaseSymbol(val); return 0; } #define RscByFct(SYM,S,FCT) \ if( name==S ) { (void)FCT; ReleaseSymbol(name); return 0; } #define RSC_FIRST(C) case C: #define RSC_NEXT(C) break; case C: /* */ switch( *name ) /* */ { /* */ #ifndef MAKEDEPEND #include #endif } /* */ /* */ ERROR3("Resource ",name," unknown."); /* */ return 1; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rsc_print() ** Purpose: Print a string to the error stream as defined in ** |error.h|. The string is automatically augmented by a ** trailing newline. ** This wrapper function is used for the resource |print|. ** Arguments: ** s String to print. ** Returns: nothing **___________________________________________________ */ void rsc_print(s) /* */ String s; /* */ { ErrPrintF("%s\n",(char*)s); /* print the string itself*/ /* followed by a newline */ } /*------------------------*/ BibTool/s_parse.c0000644000175100017510000003604512646457646012664 0ustar genegene/*** s_parse.c **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String s_parse _ARG((int type,String *sp,int errp));/* s_parse.c */ int sp_open _ARG((String s)); /* s_parse.c */ void sp_close _ARG((void)); /* s_parse.c */ int sp_expect _ARG((String*sp, String expect)); /* s_parse.c */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ #define Error(E,S,A,B) \ if(E) error(ERR_ERROR|ERR_POINT,A,(String)B,(String)0,sp_line,(String)S,0,(char*)0) static String sp_line = StringNULL; /*----------------------------------------------------------------------------- ** Function: sp_open() ** Purpose: Open a string for parsing. The argument string is used ** for the parsing process. Thus this string should not ** be modified during this time. Especially it should ** not be freed if it is a pointer to dynamically ** allocated memory. ** Arguments: ** s String to open for parsing. ** Returns: |TRUE| **___________________________________________________ */ int sp_open(s) /* */ String s; /* */ { sp_line = s; /* */ return TRUE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: s_parse() ** Purpose: Parse a string for a certain entity. Leading ** whitespace is ignored. |type| determines which kind of ** entity should be expected. It can take the following ** values which are defined in |s_parse.h|: ** \begin{description} ** \item[StringParseValue] The string is analyzed and the ** proper type is determined automatically. This can be ** considered as the normal way of operation. ** \item[StringParseSymbol] The string is analyzed and ** only a symbol is accepted, i.e.\ a sequence of ** allowed characters. ** \item[StringParseNumber] The string is analyzed and ** only a number is accepted. ** \item[StringParseBraces] The string is analyzed and ** only an expression in braces is accepted. The braced ** contained must come in matching pairs. The whole ** expression -- including the braces -- is returned. ** \item[StringParseUnquotedBraces] The string is analyzed and ** only an expression in braces is accepted. The braced ** contained must come in matching pairs. The ** expression without the outer braces is returned. ** \item[StringParseString] The string is analyzed and ** only a string enclosed in double quotes is ** accepted. The string must contain braces in matching ** pairs. Double quotes which are inside of braces are ** not considered as end of the string. The whole ** string -- including the double quotes is returned. ** \item[StringParseUnquotedString] The string is analyzed and ** only a string enclosed in double quotes is ** accepted. The string must contain braces in matching ** pairs. Double quotes which are inside of braces are ** not considered as end of the string. The string ** without the outer double quotes is returned. ** \item[StringParseSkip] The string is analyzed and the ** first position not containing whitespace, |=|, or |#| ** is returned. In this case the returned value is not ** translated into a symbol. ** \item[StringParseEOS] The string is analyzed and any ** remaining characters which are not whitespace are ** reported as error. A pointer to the terminating 0 byte ** is returned upon success ** \end{description} ** If an error occurs or the requested entity is not ** found then |NULL| is returned. As a side effect |sp| ** is advanced to point to the next unprocessed ** character. ** ** The string analyzed should be opened at the beginning ** with |sp_open()| in order to get an appropriate error ** message. ** ** This function is usually not called directly but the ** convenience macros defined in |s_parse.h| should be ** used instead. ** Arguments: ** type is the type of construct to parse. it is defined in s_parse.h ** sp is a pointer to the string which is parsed. The value is ** changed to hold the remaining characters at the end. ** errp this boolean indicated whether or not a verbose error ** message should be created in case of an error. ** Returns: A symbol containing the requested entity or |NULL|. **___________________________________________________ */ String s_parse(type, sp, errp) /* */ int type; /* */ String *sp; /* */ int errp; /* */ { register String s = *sp; /* */ Uchar c; /* */ String cp; /* */ static String unexpected = (String)"Unexpected ";/* */ static String expected = (String)" expected.";/* */ /* */ DebugPrint2((type == StringParseSkip ? "ParseSkip ": type == StringParseNext ? "ParseNext ": type == StringParseNumber ? "ParseNumber ": type == StringParseSymbol ? "ParseSymbol ": type == StringParseString ? "ParseString ": type == StringParseUnquotedString ? "ParseUnquotedString ": type == StringParseBraces ? "ParseBraces ": type == StringParseUnquotedBraces ? "ParseUnquotedBraces ": type == StringParseEOS ? "ParseEOS ": type == StringParseValue ? "ParseValue ": "???"),s); /* */ while( is_space(*s) ) s++; /* */ *sp = s; /* */ /* */ switch ( type ) /* */ { case StringParseSymbol: /* */ if ( is_allowed(*s) ) /* */ { do { s++; } while ( is_allowed(*s) ); /* */ } /* */ else /* */ { Error(errp,s,"Symbol",expected); /* */ return NULL; /* */ } /* */ break; /* */ /* */ case StringParseNumber: /* */ if ( is_digit(*s) ) /* */ { do { s++; } while ( is_digit(*s) ); /* */ } /* */ else /* */ { Error(errp,s,"Number",expected); /* */ return NULL; /* */ } /* */ break; /* */ /* */ case StringParseBraces: /* */ case StringParseUnquotedBraces: /* */ if ( *s != '{' ) /* */ { Error(errp,s,"Brace",expected); /* */ return NULL; /* */ } /* */ s++; /* */ if ( type == StringParseUnquotedBraces ) /* */ { *sp = s; } /* */ { int level = 1; /* */ /* */ while ( *s && level > 0 ) /* */ { /* */ switch ( *s ) /* */ { case '{': level++; break; /* */ case '}': --level; break; /* */ case '"': /* */ s++; /* */ while (*s && *s != '"') /* */ { if (*s != '\\' || *++s ) s++; /* */ } /* */ break; /* */ } /* */ if ( *s ) s++; /* */ } /* */ if ( level > 0 ) /* */ { Error(errp,s,unexpected,"end of braces.");/* */ } /* */ else if ( type==StringParseUnquotedBraces )/* */ { s--; } /* */ } /* */ break; /* */ /* */ case StringParseString: /* */ case StringParseUnquotedString: /* */ if ( *s != '"' ) /* */ { Error(errp,s,"String",expected); /* */ return NULL; /* */ } /* */ s++; /* */ if ( type == StringParseUnquotedString ) /* */ { *sp = s; } /* */ /* */ while ( *s && *s != '"' ) /* */ { if ( *s == '\\' && *(s+1) != '\0' ) s += 2;/* */ else ++s; /* */ } /* */ /* */ if ( *s == '"' ) /* */ { if ( type != StringParseUnquotedString ) s++;/* */ } /* */ else /* */ { Error(errp,s,unexpected,"end of string."); /* */ } /* */ break; /* */ /* */ case StringParseSkip: /* */ while( is_space(*s) /* */ || *s == '=' /* */ || *s == '#' ) s++; /* */ *sp = s; /* */ return s; /* */ /* */ case StringParseValue: /* */ switch ( *s ) /* */ { case '"': /* */ return s_parse(StringParseUnquotedString,sp,errp);/* */ case '{': /* */ return s_parse(StringParseUnquotedBraces,sp,errp);/* */ case '0': case '1': case '2': case '3': /* */ case '4': case '5': case '6': case '7': /* */ case '8': case '9': /* */ return s_parse(StringParseNumber,sp,errp);/* */ default: /* */ return s_parse(StringParseSymbol,sp,errp);/* */ } /* */ break; /* */ /* */ case StringParseEOS: /* */ if ( *s ) /* */ { Error(errp,s,unexpected,"characters at end of string.");/* */ } /* */ /* */ sp_line = NULL; /* */ return (*s ? s : NULL); /* */ /* */ default: /* */ return NULL; /* */ } /* */ /* */ c = *s; /* */ *s = (Uchar)'\0'; /* */ cp = new_Ustring(*sp); /* */ *s = c; /* */ if ( type == StringParseUnquotedString /* */ || type == StringParseUnquotedBraces ) s++; /* */ *sp = s; /* */ if (type == StringParseSymbol) /* */ { (void)lower(cp); } /* */ /* */ { String sym = symbol(cp); /* */ free(cp); /* */ return sym; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sp_expect() ** Type: int ** Purpose: ** ** Arguments: ** sp ** expect ** Returns: **___________________________________________________ */ int sp_expect(sp, expect) /* */ String *sp; /* */ String expect; /* */ { String s = *sp; /* */ /* */ while( is_space(*s) ) s++; /* */ *sp = s; /* */ /* */ for ( ;*expect; expect++) /* */ { if (*expect != *s) { return FALSE; } /* */ s++; /* */ } /* */ /* */ *sp = s; /* */ return TRUE; /* */ } /*------------------------*/ BibTool/symbols.c0000644000175100017510000004666112646457670012722 0ustar genegene/*** symbols.c **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions which deal with symbols and ** general memory management. ** This module implements a single symbol table. ** ** This module required initialization before all functions can ** be used. Especially the symbol table does not exist before ** initialization. ** ******************************************************************************/ #include #include #include #include "config.h" /*----------------------------------------------------------------------------- ** Typedef*: StringTab ** Purpose: This is the pointer type representing an entry in the symbol ** table. It contains a string and some integers. ** **___________________________________________________ */ typedef struct STAB /* */ { String st_name; /* The string representation of the symbol */ int st_count; /* */ int st_flags; /* Bits of certain flags. */ int st_used; /* Counter for determining the number of uses*/ struct STAB *st_next; /* Pointer to the next item. */ } *StringTab; /*----------------------------------------------------------------------------- ** Macro*: NextSymbol() ** Type: StringTab ** Purpose: The next |StringTab| of the argument. This macro ** can also be used as lvalue. ** Arguments: ** ST Current |StringTab| ** Returns: The next |StringTab| or |NULL|. **___________________________________________________ */ #define NextSymbol(ST) ((ST)->st_next) /*----------------------------------------------------------------------------- ** Macro*: SymbolCount() ** Type: int ** Purpose: The count slot of a |StringTab|. This macro ** can also be used as lvalue. ** Arguments: ** ST Current |StringTab| ** Returns: The count slot of |ST|. **___________________________________________________ */ #define SymbolCount(ST) ((ST)->st_count) /*----------------------------------------------------------------------------- ** Macro*: SymbolUsed() ** Type: int ** Purpose: The used slot of a |StringTab|. This macro ** can also be used as lvalue. ** Arguments: ** ST Current |StringTab| ** Returns: The used slot of |ST|. **___________________________________________________ */ #define SymbolUsed(ST) ((ST)->st_used) /*----------------------------------------------------------------------------- ** Macro*: SymbolName() ** Type: String ** Purpose: The name slot of a |StringTab|, i.e.\ the string ** representation. This macro can also be used as lvalue. ** Arguments: ** ST Current |StringTab| ** Returns: The name slot of |ST|. **___________________________________________________ */ #define SymbolName(ST) ((ST)->st_name) /*----------------------------------------------------------------------------- ** Macro*: SymbolFlags() ** Type: int ** Purpose: The flags slot of a |StringTab|. This macro ** can also be used as lvalue. ** Arguments: ** ST Current |StringTab| ** Returns: The flags slot of |ST|. **___________________________________________________ */ #define SymbolFlags(ST) ((ST)->st_flags) /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String sym_add _ARG((String s, int count)); /* symbols.c */ #ifdef New String sym_extract _ARG((String ap, String ep, int count));/* symbols.c */ #endif char * new_string _ARG((char * s)); /* symbols.c */ int sym_flag _ARG((String s)); /* symbols.c */ static StringTab new_string_tab _ARG((String name,int count,int flags));/* symbols.c*/ static int hashindex _ARG((String s)); /* symbols.c */ void init_symbols _ARG((void)); /* symbols.c */ #ifdef SYMBOL_DUMP void sym_dump _ARG((void)); /* symbols.c */ #endif void sym_gc _ARG((void)); /* symbols.c */ void sym_set_flag _ARG((String s, int flags)); /* symbols.c */ void sym_unlink _ARG((String s)); /* symbols.c */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ #ifdef HASH_TABLE_SIZE #define HASHMAX HASH_TABLE_SIZE #else #define HASHMAX 307 #endif String sym_empty = StringNULL; /* */ String sym_crossref = StringNULL; /* */ /*****************************************************************************/ /*** Misc string allocation routine ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: new_string() ** Purpose: Allocate a space for a string and copy the argument ** there. Note this is just a new copy of the memory not ** a symbol! ** ** If no more memory is available then an error is raised ** and the program is terminated. ** Arguments: ** s String to duplicate ** Returns: Pointer to newly allocated memory containing a ** duplicate of the argument string. **___________________________________________________ */ char * new_string(s) /* */ register char * s; /* */ { register char * t; /* */ if ( (t=malloc((size_t)strlen(s)+1)) == NULL ) /* */ { OUT_OF_MEMORY("string"); } /* */ (void)strcpy(t,s); /* */ return(t); /* */ } /*------------------------*/ /*****************************************************************************/ /*** Symbol Table Section ***/ /*****************************************************************************/ /*----------------------------------------------------------------------------- ** Function: new_string_tab() ** Purpose: Allocate a new |StringTab| structure and fill it with initial ** values. ** ** If no more memory is available then an error is raised ** and the program is terminated. ** Arguments: ** name String value of the |StringTab| node. ** count Initial use count of the |StringTab| node. ** flags Flags of the new |StringTab| node. ** Returns: Pointer to a new instance of a |StringTab|. **___________________________________________________ */ static StringTab new_string_tab(name, count, flags)/* */ String name; /* */ int count; /* */ int flags; /* */ { register StringTab new; /* */ /* */ if ( (new=(StringTab)malloc(sizeof(struct STAB))) == 0L )/* */ { OUT_OF_MEMORY("StringTab"); } /* */ SymbolName(new) = name; /* */ SymbolCount(new) = count; /* */ SymbolFlags(new) = flags; /* */ SymbolUsed(new) = 0; /* */ NextSymbol(new) = (StringTab)0; /* */ return(new); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: hashindex() ** Purpose: Compute the sum of ASCII values modulo |HASHMAX| ** to be used as an hash index. ** Arguments: ** s string to be analyzed. ** Returns: hash index **___________________________________________________ */ static int hashindex(s) /* */ String s; /* */ { int index = 0; /* */ while ( *s ) index = (index+*(s++)) % HASHMAX; /* */ return ( index < 0 ? -index : index ); /* */ } /*------------------------*/ static StringTab sym_tab[HASHMAX]; /*----------------------------------------------------------------------------- ** Function: init_symbols() ** Purpose: Initialize the symbols module. ** The symbol table is cleared. This is not secure when ** the symbols have already been initialized because it ** would lead to a memory leak and a violation of the ** symbol comparison assumption. Thus this case is caught ** and nothing is done when the initialization seems to ** be requested for the second time. ** ** If no more memory is available then an error is raised ** and the program is terminated. ** ** Note that this function is for internal purposes ** only. The normal user should call |init_bibtool()| ** instead. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void init_symbols() /* */ { register int i; /* */ /* */ if ( sym_empty != NULL ) return; /* */ for ( i = 0; i < HASHMAX; i++ ) sym_tab[i] = NULL;/* */ sym_empty = sym_add(new_Ustring(""),-1); /* */ sym_crossref = sym_add(new_Ustring("crossref"),-1); /* */ } /*------------------------*/ static StringTab last_stp = NULL; /*----------------------------------------------------------------------------- ** Function: sym_flag() ** Purpose: Get the flags of the symbol given as argument. ** Arguments: ** s Symbol ** Returns: The flags of the recently touched |StringTab|. **___________________________________________________ */ int sym_flag(s) /* */ String s; /* */ { /* */ if ( last_stp == NULL || SymbolName(last_stp) != s )/* */ { s = sym_add(s,0); } /* */ return SymbolFlags(last_stp); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sym_set_flag() ** Purpose: Add the flags to the symbol corresponding to the ** argument |s| by oring them together with the given ** value. ** Arguments: ** s Symbol to augment. ** flags New flags to add. ** Returns: nothing **___________________________________________________ */ void sym_set_flag(s,flags) /* */ register String s; /* */ register int flags; /* */ { /* */ if ( last_stp == NULL /* */ || SymbolName(last_stp) != s ) /* */ { s = sym_add(s,0); } /* */ SymbolFlags(last_stp) |= flags; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sym_add() ** Purpose: Add a symbol to the global symbol table. If the string ** already has a symbol assigned to it then this symbol ** is returned. If the symbol is not static then the use ** count is incremented by |count|. ** ** If the symbol does not exist already then a new symbol ** is added to the symbol table and the use count is ** initialized to |count|. A negative value for |count| ** indicates that a static symbol is requested. A static ** symbol will never bee deleted from the symbol ** table. Static can be used at places where one does not ** care about the memory occupied. ** ** If no more memory is available then an error is raised ** and the program is terminated. ** ** See also the macro |symbol()| in |symbols.h| for a ** convenient alternative to this function. ** Arguments: ** s String which should be translated into a symbol. ** count The use count which should be added to the symbol ** Returns: The new symbol. **___________________________________________________ */ String sym_add(s,count) /* */ register String s; /* */ register int count; /* */ { register StringTab *stp; /* */ /* */ if ( s == StringNULL ) return StringNULL; /* ignore dummies. */ /* */ for ( stp = &sym_tab[hashindex(s)]; /* */ *stp != NULL; /* */ stp = &NextSymbol(*stp) ) /* */ { /* */ if ( strcmp((char*)s,(char*)SymbolName(*stp)) == 0 )/* */ { if ( count > 0 ) SymbolCount(*stp) += count; /* */ last_stp = *stp; /* */ if ( s != SymbolName(*stp) ) /* */ { SymbolUsed(*stp)++; } /* */ return SymbolName(*stp); /* */ } /* */ } /* */ if ( count >= 0 ) /* */ { s = new_Ustring(s); } /* */ *stp = new_string_tab(s,count<0?0:count,0); /* */ last_stp = *stp; /* */ SymbolUsed(*stp)++; /* */ if ( count < 0 ) /* */ { SymbolFlags(*stp) ^= SYMBOL_STATIC; /* */ } /* */ return SymbolName(*stp); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sym_unlink() ** Purpose: Free a symbol since it is no longer used. ** This does not mean that the memory is also freed. The ** symbol can be static or used at other places. The real ** free operation requires that the garbage collector ** |sym_gc()| to be called. ** ** If the argument is |NULL| or an arbitrary string (no ** symbol) then this case is also dealt with. ** Arguments: ** s Symbol to be released. ** Returns: nothing **___________________________________________________ */ void sym_unlink(s) /* */ register String s; /* */ { register StringTab st; /* */ /* */ if ( s == NULL ) return; /* ignore dummies. */ /* */ for ( st = sym_tab[hashindex(s)]; /* */ st != NULL; /* */ st = NextSymbol(st) ) /* */ { if ( s == SymbolName(st) ) /* */ { SymbolUsed(st)--; /* reduce reference count */ return; /* */ } /* */ } /* */ #ifdef DEBUG ErrPrintF("*** Attempt to free an undefined symbol: %s\n",s);/* */ #endif } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function*: sym_gc() ** Purpose: This is the garbage collector. It analyzes the symbol ** table and releases all |SymbolTab| nodes not needed ** any more. ** ** Right now it is purely experimental. Better let your ** hands off. ** ** Arguments: none ** Returns: nothing **___________________________________________________ */ void sym_gc() /* */ { /* */ register StringTab st, st2; /* */ register int i; /* */ /* */ for ( i=0;i #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String pop_string _ARG((void)); /* stack.c */ void push_string _ARG((String s)); /* stack.c */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ static String *stack; static size_t stack_size = 0; static size_t stack_ptr = 0; /*----------------------------------------------------------------------------- ** Function: push_string() ** Purpose: Push a string onto the stack. Only the memory for the ** stack is allocated. The string is stored as pointer to ** existing memory. No copy of the string is made. ** ** If no memory is left then an error is raised and the program ** is terminated. ** Arguments: ** s String to push to the stack. ** Returns: nothing **___________________________________________________ */ void push_string(s) /* */ register String s; /* */ { /* */ if ( stack_ptr >= stack_size ) /* */ { stack_size += 16; /* */ stack = (stack_ptr == 0 /* */ ?(String*)malloc((size_t)(stack_size*sizeof(String)))/* */ :(String*)realloc((char*)stack, /* */ (size_t)(stack_size*sizeof(String))));/* */ if ( stack == NULL ) /* */ { OUT_OF_MEMORY("stack"); } /* */ } /* */ stack[stack_ptr++] = s; /* */ DebugPrint2("pushing ",s); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: pop_string() ** Purpose: Pop a string from the stack. It the stack is empty ** then |NULL| is returned. Thus the |NULL| value should ** not be pushed to the stack since this can be confused ** with the end of the stack. ** Arguments: none ** Returns: The old top element or |NULL| if the stack is empty. **___________________________________________________ */ String pop_string() /* */ { /* */ if ( stack_ptr <= 0 ) return NULL; /* */ /* */ DebugPrint2("poping ",stack[stack_ptr-1]); /* */ return stack[--stack_ptr]; /* */ } /*------------------------*/ BibTool/sbuffer.c0000644000175100017510000002450112646457626012654 0ustar genegene/*** sbuffer.c **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions for dealing with strings of ** aribtrary size. The allocation of memory is done automatically ** when more characters are added. ** ** The functions are modeled after the stream functions of C. ** Currently a |printf|-like function is missing because one was ** not needed yet and it is not so easy to implement---portably. ** ** The functions in this module are very handy to deal with ** strings of arbitrary length where the length is not known in ** advance. E.g. consider the case that a line has to be read ** from a file |file| and the line length should not be restricted by ** some artificial boundry. This can be implemented as follows: ** \\ ** |{ StringBuffer *sb = sb_open();|\Ccomment{Declare and ** initialize a string buffer.}\\ ** | int c;|\Ccomment{Variable to store a single character.}\\ ** | char *s;|\Ccomment{Variable to hold the string at the end.}\\ ** | while ( (c=fgetc(file) != EOF|\\ ** | && c != '\n')|\\ ** | { sbputchar(c,sb); }|\Ccomment{Store each character in the ** string buffer.}\\ ** | s = sbflush(sb);|\Ccomment{Get the string from the ** string buffer.}\\ ** | puts(s);|\Ccomment{Process the string; e.g. print it.}\\ ** | sb_close(sb);|\Ccomment{Free the string buffer.}\\ ** |}| ** ** Note that the flushing of the string buffer returns a C string ** which is managed by the string buffer. This memory is freed ** or reused whenever the string buffer needs to. Thus you should ** make a private copy of this string if it should survive the ** next operation of the string buffer. Especially, after the ** call to |sb_close()| this memory has been returned to the ** operating system and is not available any more. ** ******************************************************************************/ #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ /*----------------------------------------------------------------------------- ** Function: sbopen() ** Purpose: Allocate a new string buffer. ** Return a pointer to the new string buffer or |NULL| if ** none was available. ** Arguments: none. ** Returns: pointer to new string buffer or NULL **___________________________________________________ */ StringBuffer* sbopen() /* */ { register StringBuffer* sb; /* */ /* */ if ( (sb=(StringBuffer*)malloc(sizeof(StringBuffer))) == NULL )/* */ { return NULL; } /* */ sb->sb__string = NULL; /* */ sb->sb__ptr = sb->sb__size = 0; /* */ return sb; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sbclose() ** Purpose: Free an old string buffer. ** Arguments: ** sb Pointer to string buffer which should be closed ** Returns: Return 0 upon failure. **___________________________________________________ */ int sbclose(sb) /* */ StringBuffer* sb; /* */ { /* */ if ( sb == NULL ) return 1; /* */ if ( sb->sb__string != NULL ) free(sb->sb__string);/* */ free((char*)sb); /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sbputs() ** Purpose: Push a whole string onto a string buffer. ** Arguments: ** s String to be pushed. ** sb Destination string buffer. ** Returns: |FALSE| if something went wrong. **___________________________________________________ */ int sbputs(s,sb) /* */ char *s; /* */ StringBuffer* sb; /* */ { /* */ if ( sb == NULL ) return 1; /* */ /* */ while ( *s ) /* */ { (void)sbputchar(*s,sb); ++s; /* */ } /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sbputc() ** Purpose: Push a single character onto a string buffer. In ** contrast to the macro this function handles the ** reallocation of the memory. For the user it should not ** make a difference since the macros uses this function ** when needed. ** ** When no memory is left then the character is discarded ** and this action is signaled via the return value. ** Arguments: ** c Character to put to the string buffer. ** sb Destination string buffer. ** Returns: |FALSE| if no memory is left. **___________________________________________________ */ int sbputc(c,sb) /* */ register int c; /* */ register StringBuffer* sb; /* */ { register char *cp; /* */ /* */ if ( sb->sb__ptr >= sb->sb__size ) /* */ { sb->sb__size += StringBufferIncrement; /* */ if ( (cp=( sb->sb__ptr == 0 /* */ ? malloc(sb->sb__size) /* */ : realloc(sb->sb__string,sb->sb__size))/* */ ) == NULL ) /* */ { sb->sb__size -= StringBufferIncrement; /* */ return 1; /* */ } /* */ sb->sb__string = cp; /* */ } /* */ /* */ sb->sb__string[sb->sb__ptr++] = c; /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sbflush() ** Purpose: Close a string buffer with a trailing |\0| and reset the ** current pointer to the beginning. ** The next write operation starts right at the end. Thus ** additional write operations will overwrite the ** terminating byte. ** Arguments: ** sb String buffer to close. ** Returns: The string contained in the string buffer as a proper ** C string. **___________________________________________________ */ char* sbflush(sb) /* */ StringBuffer* sb; /* */ { /* */ (void)sbputchar('\0',sb); /* */ sb->sb__ptr--; /* */ return sb->sb__string; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sbrewind() ** Purpose: Reset the string buffer pointer to the beginning. ** The next write or read will operate there. ** Arguments: ** sb String buffer to consider. ** Returns: nothing **___________________________________________________ */ void sbrewind(sb) /* */ StringBuffer* sb; /* */ { sb->sb__ptr = 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sbtell() ** Purpose: Return the current pointer to the string buffer position. ** This can be used with |sbseek()| to reset it. ** Arguments: ** sb String buffer to consider. ** Returns: The relative byte position of the current writing ** position. This is an integer offset from the beginning ** of the string buffer. **___________________________________________________ */ int sbtell(sb) /* */ StringBuffer* sb; /* */ { return sb->sb__ptr; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: sbseek() ** Purpose: Reset the current pointer to the position given. If ** the position is outside the valid region then |TRUE| ** is returned and the position is left unchanged. ** Arguments: ** sb String buffer to reposition. ** pos New position of the string buffer. ** Returns: |FALSE| if everything went right. **___________________________________________________ */ int sbseek(sb,pos) /* */ StringBuffer* sb; /* */ int pos; /* */ { /* */ if ( pos < 0 || pos > sb->sb__ptr ) return 1; /* */ sb->sb__ptr = pos; /* */ return 0; /* */ } /*------------------------*/ BibTool/tex_aux.c0000644000175100017510000004117412646457676012707 0ustar genegene/*** tex_aux.c **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif static void save_ref _ARG((String s)); /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ static StringBuffer* aux_sb = (StringBuffer*)0; static int cite_star = TRUE; static WordList cite[32] = { WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL, WordNULL }; /*----------------------------------------------------------------------------- ** Function: clear_aux() ** Purpose: Reset the aux table to the initial state. ** ** ** Arguments: none ** Returns: nothing **___________________________________________________ */ void clear_aux() /* */ { int i; /* */ cite_star = TRUE; /* */ for (i = 0; i < 32; i++) /* */ { free_words(&cite[i],sym_unlink); } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: foreach_aux() ** Purpose: Apply the function to all words in the citation list of the ** aux file. ** ** Arguments: ** fct funtion to apply ** Returns: |cite_star| **___________________________________________________ */ int foreach_aux(fct) /* */ int (fct)_ARG((String)); /* */ { int i; /* */ for (i = 0; i < 32; i++) /* */ { foreach_word(cite[i], fct); } /* */ return cite_star; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: save_ref() ** Purpose: Store the cite key for selection. ** If the cite key is "*" then all should be selected. ** This is written e.g. by \nocite{*} ** Arguments: ** s ** Returns: nothing **___________________________________________________ */ static void save_ref(s) /* */ register String s; /* */ { /* */ if ( cite_star ) return; /* */ /* */ if (*s == '*' && *(s+1) == '\0') /* */ { clear_aux(); } /* */ else { add_word(symbol(s), &cite[*s&31]); } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: aux_used() ** Purpose: Check whether a reference key has been requested by the ** previously read aux file. The request can either be explicit ** or implicit if a * is used. ** Arguments: ** s reference key to check ** Returns: **___________________________________________________ */ int aux_used(s) /* */ String s; /* */ { /* */ return ( cite_star /* */ || find_word(s,cite[*s&31])); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: read_aux() ** Purpose: Analyze an aux file. If additional files are ** requested, e.g. by |\include| instructions in the ** original source file then those are read as well. Each ** citation found is remembered and can be queried ** afterwards. If a |\cite{*}| has been used then only a ** flag is set and all citation keys are discarded. ** ** The aux file contains also the information about the ** \BibTeX{} files used. For each such file the function ** |fct| is called with the file name as argument. This ** function can arrange things that those \BibTeX{} files ** are read into a database. ** ** This function has only a very simple parser for the ** aux file. Thus it can be confused by legal ** contents. But a similar thing can happen to \BibTeX{} ** as well. ** Arguments: ** fname The file name of the aux file. ** fct A function to be called for each \BibTeX{} file requested. ** verbose Boolean indicating whether messages should be produced ** indicating the status of the operation. ** Returns: |TRUE| iff the file could not be opened. **___________________________________________________ */ int read_aux(fname, fct, verbose) /* */ String fname; /* aux file name */ void (*fct)_ARG((char*)); /* */ int verbose; /* */ { FILE *file; /* */ int c; /* */ String s; /* */ /* */ cite_star = FALSE; /* */ rsc_select = TRUE; /* */ /* */ if ( (file=fopen((char*)fname,"r") ) == NULL ) /* */ { StringBuffer *sb = sbopen(); /* */ sbputs((char*)fname,sb); /* */ sbputs(".aux",sb); /* */ file = fopen(sbflush(sb),"r"); /* */ sbclose(sb); /* */ } /* */ if ( file == NULL ) /* */ { ERROR3("aux file ",fname," not found."); /* */ return TRUE; /* */ } /* */ /* */ rsc_del_q = FALSE; /* */ /* */ if ( verbose ) /* */ { VerbosePrint2("Analyzing ",fname); } /* */ /* */ if ( aux_sb == (StringBuffer*)0 ) /* */ { aux_sb = sbopen(); } /* */ /* */ for(c = getc(file); c != EOF; c = getc(file)) /* */ { if ( c == '\\' ) /* */ { for(c = getc(file); /* */ c != EOF && (is_alpha(c&0xff) || c == '@');/* */ c = getc(file)) /* */ { (void)sbputchar(c, aux_sb); } /* */ s = (String)sbflush(aux_sb); /* */ sbrewind(aux_sb); /* */ /* */ if (strcmp((char*)s, "citation") == 0 ) /* */ { do /* Save a cite key. */ { switch ( c=getc(file) ) /* */ { case EOF: break; /* */ case ',': /* */ case '}': /* */ s = (String)sbflush(aux_sb); /* */ sbrewind(aux_sb); /* */ save_ref((String)s); /* */ break; /* */ default: /* */ (void)sbputchar(ToLower(c&0xff),aux_sb);/* */ } /* */ } while ( c != '}' && c != EOF ); /* */ } /* */ else if (strcmp((char*)s, "bibdata") == 0 ) /* */ { c = getc(file); /* Save a bib file name */ (void)sbputchar((Uchar)c, aux_sb); /* */ while ( c != '}' && c != EOF ) /* */ { c = getc(file); /* */ if ( c == ',' || c == '}' ) /* */ { s = (String)sbflush(aux_sb); /* */ sbrewind(aux_sb); /* */ (*fct)((char*)symbol(s)); /* */ } /* */ else /* */ { (void)sbputchar(c, aux_sb); } /* */ } /* */ } /* */ else if (strcmp((char*)s, "@input") == 0 ) /* Read another aux file */ { while( (c=getc(file)) != '}' && c != EOF ) /* */ { (void)sbputchar(c,aux_sb); } /* */ s = (String)sbflush(aux_sb); /* */ sbrewind(aux_sb); /* */ /* */ read_aux(s, fct, verbose); /* */ } /* */ } /* */ } /* */ /* */ (void)fclose(file); /* */ /* */ #ifdef DEBUG { register int i; /* */ WordList wl; /* */ /* */ for (i = 0; i < 32; ++i) /* */ { ErrPrintF("--- BibTool: %d\n",i); /* */ for (wl = cite[i]; wl != WordNULL; wl = NextWord(wl) )/* */ { ErrPrintF("%s\n",ThisWord(wl)); } /* */ } /* */ } /* */ #endif return FALSE; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: apply_aux() ** Purpose: This function deletes all entries which are not ** requested by the recently read aux file. This means ** that the entry to be kept is either mentioned directly, ** it is crossreferenced, or all entries are requested ** with the |\nocite{*}| feature. ** ** Note that the entries are in fact not deleted but only ** marked as deleted. Thus they can be recovered if ** necessary. ** Arguments: ** db Database to clean. ** Returns: |FALSE| iff all entries are kept because of an ** explicit or implicit star (*). **___________________________________________________ */ int apply_aux(db) /* */ DB db; /* */ { Record rec, rec1; /* */ /* */ if ( cite_star ) return FALSE; /* No selection desired. */ /* */ DebugPrint1("Filtering from aux"); /* */ /* */ rec = DBnormal(db); /* */ if ( rec == RecordNULL ) return TRUE; /* No entries left anyhow.*/ /* */ while ( PrevRecord(rec) != RecordNULL ) /* Rewind */ { rec = PrevRecord(rec); } /* */ rec1 = rec; /* */ /* */ for ( ; /* Phase 1: */ rec != RecordNULL; /* Mark all entries */ rec = NextRecord(rec) ) /* contained in the aux */ { if ( *RecordHeap(rec) && /* file and unmark the */ find_word(*RecordHeap(rec), /* others. */ cite[(**RecordHeap(rec))&31]) ) /* */ { SetRecordMARK(rec); } /* */ else /* */ { ClearRecordMARK(rec); } /* */ } /* */ /* */ /* */ for ( rec = rec1; /* Phase 2: */ rec != RecordNULL; /* For all marked entries*/ rec = NextRecord(rec) ) /* which have a xref and */ { /* mark all xrefs. */ if ( RecordIsMARKED(rec) && /* */ RecordIsXREF(rec) && /* */ !RecordIsDELETED(rec) /* */ ) /* */ { String key = (String)"???"; /* */ int count; /* */ Record r = rec; /* */ /* */ for ( count = rsc_xref_limit; /* Prevent infinite loop */ count >= 0 && /* */ RecordIsXREF(r) && /* */ !RecordIsDELETED(r); /* */ count-- ) /* */ { key = get_field(db,r,sym_crossref); /* */ if ( key == NULL ) /* */ { count = -1; } /* */ else /* */ { key = symbol(lower(expand_rhs(key, /* */ sym_empty, /* */ sym_empty, /* */ db))); /* */ if ( (r=db_find(db,key)) == RecordNULL ) /* */ { ErrPrintF("*** BibTool: Crossref `%s' not found.\n",key);/* */ count = -1; /* */ } /* */ else /* */ { /* */ if ( RecordIsMARKED(r) ) /* */ { count = -1; } /* */ SetRecordMARK(r); /* */ ClearRecordDELETED(r); /* */ } /* */ } /* */ } /* */ if ( count == -1 ) /* */ { ErrPrintF("*** BibTool: Crossref limit exceeded; `%s' possibly looped.\n", key); /* */ } /* */ } /* */ } /* */ /* */ for ( rec = rec1; /* Phase 3: */ rec != RecordNULL; /* Delete unmarked */ rec = NextRecord(rec) ) /* entries. */ { if ( !RecordIsMARKED(rec) ) /* */ { SetRecordDELETED(rec); } /* */ } /* */ /* */ return TRUE; /* */ } /*------------------------*/ BibTool/tex_read.c0000644000175100017510000012041612646457722013012 0ustar genegene/*** tex_read.c *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** ** Purpose: Simulate the TeX reading mechanism. ** ** Compilation: cc tex_read.c -o tex_read -DSTANDALONE ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions which immitate the reading ** apparatus of \TeX{}. Macro expansion can be performed. ** ** ******************************************************************************/ #include #include #ifndef STANDALONE #include #include #else #define Err(X) (void)fputs(X,stderr) #define ERROR_EXIT(X) Err(X); exit(1) #define OUT_OF_MEMORY(X) Err("Out of memory for "); Err(X); exit(1) #endif /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ #define CARET_CARET /* enable ^^A type specification of unprintables */ #undef TRANSLATE_NEWLINE /* Translate nl to space or \par */ typedef struct tOKEN /* */ { short int to_char; /* */ String to_s; /* */ struct tOKEN *to_next; /* */ } *Token, SToken; /* */ #define TokenChar(X) ((X)->to_char) #define TokenSeq(X) ((X)->to_s) #define NextToken(X) ((X)->to_next) #define TokenNULL (Token)0 typedef struct mACdEF /* */ { short int md_arity; /* */ String md_name; /* */ Token md_token; /* */ struct mACdEF *md_next; /* */ } *MacDef, SMacDef; /* */ #define MacroArity(X) ((X)->md_arity) #define MacroName(X) ((X)->md_name) #define MacroToken(X) ((X)->md_token) #define NextMacro(X) ((X)->md_next) #define MacDefNULL (MacDef)0 /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int TeX_read _ARG((String cp,String *sp)); /* tex_read.c */ static MacDef find_macro _ARG((String name,MacDef md));/* tex_read.c */ static MacDef new_macdef _ARG((String name,int arity,Token tokens));/* tex_read.c*/ static Token TeX_get_token _ARG((int (*get_fct)_ARG((void))));/* tex_read.c */ static Token new_token _ARG((int type,String string));/* tex_read.c */ static Token token_list_copy _ARG((Token t,Token nt,Token *argp));/* tex_read.c*/ static Token tokenize _ARG((String s,int arity)); /* tex_read.c */ static int TeX_fill_line _ARG((int (*get_fct)_ARG((void))));/* tex_read.c */ static int do_get _ARG((void)); /* tex_read.c */ static int fill_token _ARG((Token*tp)); /* tex_read.c */ static int get_EOF _ARG((void)); /* tex_read.c */ static int get_file _ARG((void)); /* tex_read.c */ static int get_string _ARG((void)); /* tex_read.c */ static String tokens_to_string _ARG((Token t)); /* tex_read.c */ static void free_1_token _ARG((Token t)); /* tex_read.c */ static void free_macdef _ARG((MacDef mac)); /* tex_read.c */ static void free_tokens _ARG((Token t)); /* tex_read.c */ static void init_TeX _ARG((void)); /* tex_read.c */ static void init_get _ARG((String s)); /* tex_read.c */ void TeX_active _ARG((int c,int arity,String s));/* tex_read.c */ void TeX_close _ARG((void)); /* tex_read.c */ void TeX_def _ARG((String s)); /* tex_read.c */ void TeX_define _ARG((String name,int arity,String body));/* tex_read.c */ void TeX_open_file _ARG((FILE * file)); /* tex_read.c */ void TeX_open_string _ARG((String s)); /* tex_read.c */ void TeX_reset _ARG((void)); /* tex_read.c */ #ifdef STANDALONE int main _ARG((int argc,char *argv[])); /* tex_read.c */ static char * new_string _ARG((char * s)); /* tex-read.c */ static void show_tokens _ARG((Token t)); /* tex-read.c */ #else extern char * new_string _ARG((char * s)); #endif /*---------------------------------------------------------------------------*/ /*****************************************************************************/ /*** catcode Management. ***/ /*****************************************************************************/ #define CHAR_ESCAPE '\\' #define CHAR_BEG_GROUP '{' #define CHAR_END_GROUP '}' #define CHAR_MATH '$' #define CHAR_ALIGN '&' #define CHAR_EOL '\n' #define CHAR_PARAMETER '#' #define CHAR_SUPERSCRIPT '^' #define CHAR_SUBSCRIPT '_' #define CHAR_IGNORED '\0' #define CHAR_SPACE ' ' #define CHAR_COMMENT '%' #define CATCODE_ESCAPE 0x0000 #define CATCODE_BEG_GROUP 0x0100 #define CATCODE_END_GROUP 0x0200 #define CATCODE_MATH 0x0300 #define CATCODE_ALIGN 0x0400 #define CATCODE_EOL 0x0500 #define CATCODE_PARAMETER 0x0600 #define CATCODE_SUPERSCRIPT 0x0700 #define CATCODE_SUBSCRIPT 0x0800 #define CATCODE_IGNORED 0x0900 #define CATCODE_SPACE 0x0A00 #define CATCODE_LETTER 0x0B00 #define CATCODE_OTHER 0x0C00 #define CATCODE_ACTIVE 0x0D00 #define CATCODE_COMMENT 0x0E00 #define CATCODE_INVALID 0x0F00 #define CATCODE_MASK 0x0F00 static short int catcode[256]; static MacDef macro = MacDefNULL; static MacDef active[256]; #define EnsureInit init_TeX() /*----------------------------------------------------------------------------- ** Function: init_TeX() ** Purpose: Initialize the \TeX{} reading apparatus. ** Mainly the catcodes are assigned and the macros are ** cleared. This function has to be called before the ** other functions in this module. Thus this function is ** called automatically from different places to ensure ** that the reading apparatus is initialized. ** Arguments: none ** Returns: nothing **___________________________________________________ */ static void init_TeX() /* */ { register int i; /* */ static int initialized = FALSE; /* */ /* */ if ( initialized ) return; /* */ initialized = TRUE; /* */ /* */ for ( i=0; i<256; ++i ) /* */ { active[i] = MacDefNULL; /* */ catcode[i] = ( isalpha(i) /* */ ? CATCODE_LETTER /* */ : CATCODE_OTHER ); /* */ } /* */ catcode[CHAR_ESCAPE] = CATCODE_ESCAPE; /* */ catcode[CHAR_BEG_GROUP] = CATCODE_BEG_GROUP; /* */ catcode[CHAR_END_GROUP] = CATCODE_END_GROUP; /* */ catcode[CHAR_MATH] = CATCODE_MATH; /* */ catcode[CHAR_ALIGN] = CATCODE_ALIGN; /* */ catcode[CHAR_EOL] = CATCODE_EOL; /* */ catcode[CHAR_PARAMETER] = CATCODE_PARAMETER; /* */ catcode[CHAR_SUPERSCRIPT] = CATCODE_SUPERSCRIPT; /* */ catcode[CHAR_SUBSCRIPT] = CATCODE_SUBSCRIPT; /* */ catcode[CHAR_IGNORED] = CATCODE_IGNORED; /* */ catcode[CHAR_SPACE] = CATCODE_SPACE; /* */ catcode[CHAR_COMMENT] = CATCODE_COMMENT; /* */ catcode['~'] = CATCODE_ACTIVE; /* */ } /*------------------------*/ /*****************************************************************************/ /*** Token Management. ***/ /*****************************************************************************/ static Token token_free_list = TokenNULL; /*----------------------------------------------------------------------------- ** Function: new_token() ** Purpose: Allocate a new token cell and fill it with values. ** Arguments: ** type the type ** string the strign value ** Returns: the new token **___________________________________________________ */ static Token new_token(type, string) /* */ int type; /* */ String string; /* */ { Token new; /* */ /* */ if ( token_free_list != TokenNULL ) /* */ { new = token_free_list; /* */ token_free_list = NextToken(token_free_list); /* */ } /* */ else if ( (new=(Token)malloc(sizeof(SToken))) == TokenNULL )/* */ { OUT_OF_MEMORY("TeX token."); } /* */ /* */ TokenChar(new) = type; /* */ TokenSeq(new) = string; /* */ NextToken(new) = TokenNULL; /* */ return new; /* */ } /*------------------------*/ #define CopyToken(t) new_token(TokenChar(t), \ TokenSeq(t) ? new_Ustring(TokenSeq(t)) : NULL) #define NewToken(C) new_token(C, StringNULL) /*----------------------------------------------------------------------------- ** Function: token_list_copy() ** Purpose: Copy a list of tokens. ** Arguments: ** t ** nt ** argp ** Returns: **___________________________________________________ */ static Token token_list_copy(t,nt,argp) /* */ register Token t; /* */ Token nt; /* */ Token *argp; /* */ { register Token a,p; /* */ int i; /* */ /* */ if ( t == TokenNULL ) return TokenNULL; /* */ if ( (i=TokenChar(t)) > 0xff ) /* */ { a = p = token_list_copy(argp[i>>8],TokenNULL,argp);/* */ while ( NextToken(p) != TokenNULL ) /* */ { p = NextToken(p); } /* */ } /* */ else { a = p = CopyToken(t); } /* */ /* */ while ( (t=NextToken(t)) != TokenNULL ) /* */ { /* */ if ( (i=TokenChar(t)) > 0xff ) /* */ { NextToken(p) = token_list_copy(argp[i>>8],TokenNULL,argp);/* */ while ( NextToken(p) != TokenNULL ) /* */ { p = NextToken(p); } /* */ } /* */ else /* */ { NextToken(p) = CopyToken(t); /* */ p = NextToken(p); /* */ } /* */ } /* */ NextToken(p) = nt; /* */ return a; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_1_token() ** Purpose: Free a single Token. ** Free the string and place it in the free list. ** Arguments: ** t ** Returns: nothing **___________________________________________________ */ static void free_1_token(t) /* */ register Token t; /* */ { NextToken(t) = token_free_list; /* */ token_free_list = t; /* */ if ( TokenSeq(t) ) free(TokenSeq(t)); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_tokens() ** Purpose: Free a list of Tokens. ** Walk along to the end and free the strings on the way. ** Link it into the free list. ** Arguments: ** t ** Returns: nothing **___________________________________________________ */ static void free_tokens(t) /* */ register Token t; /* */ { register Token t0; /* */ /* */ for ( t0 = t; /* */ NextToken(t0) != TokenNULL; /* */ t0 = NextToken(t0) ) /* */ { if ( TokenSeq(t0) ) free(TokenSeq(t0)); } /* */ /* */ if ( TokenSeq(t0) ) free(TokenSeq(t0)); /* */ NextToken(t0) = token_free_list; /* */ token_free_list = t; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: tokens_to_string() ** Purpose: Make a string out of a list of tokens. ** Arguments: ** t ** Returns: **___________________________________________________ */ static String tokens_to_string(t) /* */ Token t; /* */ { register Token t1; /* */ register String s, /* */ sp; /* */ register int len; /* */ /* */ for (len = 1, t1 = t; /* Count the elements of */ t1 != TokenNULL; /* the token list. */ t1 = NextToken(t1)) /* (+1 for '\0') */ { ++len; } /* */ /* */ if ( (s=(String)malloc(len * sizeof(Uchar))) /* */ == NULL ) /* Try to get */ { OUT_OF_MEMORY("TeX string."); } /* new memory. */ /* */ for (sp = s, t1 = t; /* Transfer the characters*/ t1 != TokenNULL; /* from the token list */ t1 = NextToken(t1)) /* to the string. */ { *(sp++) = TokenChar(t1); } /* */ *sp = '\0'; /* */ return s; /* Return the string. */ } /*------------------------*/ /*****************************************************************************/ /*** Reading Apparatus. ***/ /*****************************************************************************/ #define StateN 0 #define StateM 1 #define StateS 2 static int tex_state = StateN; /* */ static Token tex_line = TokenNULL; /* */ #define tex_clear tex_state = StateN; tex_line = TokenNULL /*----------------------------------------------------------------------------- ** Function: TeX_fill_line() ** Purpose: ** ** ** Arguments: ** get_fct ** Returns: **___________________________________________________ */ static int TeX_fill_line(get_fct) /* */ int (*get_fct)_ARG((void)); /* function * to get char */ { register int c; /* */ register Token t; /* */ register int spaces = 0; /* */ /* */ if ( (c=(*get_fct)()) == EOF ) return 1; /* */ tex_line = t = NewToken(c); /* */ /* */ while ( (c=(*get_fct)()) != EOF && c != '\n' ) /* */ { if ( isspace(c) ) { ++spaces; } /* Spaces are delayed. */ else /* */ { while ( spaces > 0 ) /* */ { NextToken(t) = NewToken(CHAR_SPACE); /* */ t = NextToken(t); /* */ spaces--; /* */ } /* */ NextToken(t) = NewToken(c); /* */ t = NextToken(t); /* */ } /* */ } /* */ if ( TokenChar(t) == CHAR_SPACE ) TokenChar(t) = CHAR_EOL;/* */ else NextToken(t) = NewToken(CHAR_EOL); /* */ /* */ #ifdef CARET_CARET { register Token *tp; /* */ for ( tp= &tex_line; /* Loop over the read */ *tp!=TokenNULL; /* line. */ tp= &NextToken(*tp) ) /* */ { t = NextToken(*tp); /* */ if ( TokenChar(*tp) == '^' /* Translate ^^. */ && TokenChar(t=NextToken(*tp)) == '^' /* to single characters */ && (c=TokenChar(NextToken(t))) != '\n' ) /* */ { NextToken(*tp) = NextToken(NextToken(t)); /* */ free_1_token(NextToken(t)); /* */ free_1_token(t); /* */ TokenChar(*tp) = (c >= 64 ? c - 64 : c + 64);/* */ } /* */ } /* */ } /* */ #endif /* */ return 0; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: TeX_get_token() ** Purpose: Get characters and pack them into a Token structure. ** The argument is a function called to get the next character. ** It returns the next character of EOF if no more can be read. ** Arguments: ** get_fct ** Returns: **___________________________________________________ */ static Token TeX_get_token(get_fct) /* */ int (*get_fct)_ARG((void)); /* function * to get char */ { register Token t, t1, t2; /* */ /* */ for (;;) /* */ { /* */ if ( tex_line == TokenNULL /* */ && TeX_fill_line(get_fct) ) /* */ { return TokenNULL; } /* */ /* */ t = tex_line; /* */ tex_line = NextToken(t); /* */ NextToken(t) = TokenNULL; /* */ /* */ switch ( TokenChar(t) ) /* */ { case CHAR_IGNORED: /* */ break; /* */ #ifdef TRANSLATE_NEWLINE case CHAR_EOL: /* */ switch (tex_state) /* */ { case StateN: /* */ TokenChar(t) = CHAR_ESCAPE; /* */ TokenSeq(t) = new_Ustring("par"); /* */ return t; /* */ case StateM: /* */ TokenChar(t) = CHAR_SPACE; /* */ return t; /* */ } /* */ #endif case CHAR_COMMENT: /* */ free_tokens(tex_line); /* */ tex_line = TokenNULL; /* */ break; /* */ case CHAR_SPACE: /* */ if ( tex_state == StateM ) /* */ { tex_state = StateS; /* */ return t; /* */ } /* */ break; /* */ case CHAR_ESCAPE: /* */ t1 = tex_line; /* */ if ( isalpha(TokenChar(tex_line)) ) /* */ { while ( isalpha(TokenChar(NextToken(tex_line))) )/* */ { tex_line = NextToken(tex_line); } /* */ } /* */ else if ( TokenChar(tex_line) == CHAR_EOL )/* */ { tex_state = StateM; /* */ TokenSeq(t) = new_Ustring(""); /* */ return t; /* */ } /* */ t2 = tex_line; /* */ tex_line = NextToken(tex_line); /* */ NextToken(t2) = TokenNULL; /* */ TokenSeq(t) = tokens_to_string(t1); /* */ free_tokens(t1); /* */ tex_state = StateM; /* */ return t; /* */ /* */ default: /* */ tex_state = StateM; /* */ return t; /* */ } /* */ free_1_token(t); /* */ } /* */ } /*------------------------*/ static String g_s; /* */ static String g_p; /* */ /*----------------------------------------------------------------------------- ** Function: init_get() ** Purpose: ** ** ** Arguments: ** s ** Returns: nothing **___________________________________________________ */ static void init_get(s) /* */ register String s; /* */ { g_p = g_s = s; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: do_get() ** Purpose: ** ** ** Arguments: ** ** Returns: **___________________________________________________ */ static int do_get() /* */ { return ( *g_p == '\0' ? EOF : *(g_p++)); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: tokenize() ** Purpose: ** ** ** Arguments: ** s ** arity ** Returns: **___________________________________________________ */ static Token tokenize(s, arity) /* */ String s; /* */ int arity; /* */ { Token t = TokenNULL, /* */ t_ret = TokenNULL, /* */ nt, t0; /* */ int a; /* */ /* */ EnsureInit; /* */ init_get(s); /* */ /* */ while ( (nt=TeX_get_token(do_get)) != TokenNULL )/* */ { if ( TokenChar(nt) =='\n' ) /* */ { free_1_token(nt); } /* */ else /* */ { if ( TokenChar(nt) == CHAR_PARAMETER /* */ && (t0=TeX_get_token(do_get)) != TokenNULL )/* */ { a = TokenChar(t0) - '0'; /* */ if ( 0 arity || arity > 9 ) return; /* */ /* */ md = new_macdef(name, /* */ arity, /* */ tokenize(body,arity));/* */ NextMacro(md) = macro; /* */ macro = md; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: TeX_def() ** Purpose: Define a macro. ** The argument is a string specification of the following form: ** ** |\name[arity]=replacement text|\\ ** |\name=replacement text| ** ** \(0 <= arity <= 9\) ** Arguments: ** s ** Returns: nothing **___________________________________________________ */ void TeX_def(s) /* */ String s; /* */ { String name, /* */ ep = NULL; /* */ int arity = 0; /* */ /* */ while( isspace(*s) ) s++; /* */ name = s; /* */ while ( *s && *s != '=' ) /* */ { if ( *s == '[' ) /* */ { arity = *(s+1) - '0'; ep = s; } /* */ ++s; /* */ } /* */ /* */ if ( ep == NULL ) ep = s; /* */ /* */ if ( *name == '\\' ) /* */ { char c; /* */ while (ep > name + 2 && /* */ (*(ep-1) == ' ' || *(ep-1) =='\t')) /* */ { ep--; } /* */ c = *ep; *ep = '\0'; /* */ TeX_define(new_Ustring(name + 1), /* */ arity, /* */ new_Ustring(s + 1)); /* */ *ep = c; /* */ } /* */ else /* */ { TeX_active((unsigned int)*name, /* */ arity, /* */ new_Ustring(s+1)); /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: TeX_active() ** Purpose: Assign a macro to an active character. If the ** character is not active then the catcode is changed. ** Arguments: ** c Character to make active. ** arity Arity of the macro assigned to the active character. ** s Body of the definition as string. ** Returns: nothing **___________________________________________________ */ void TeX_active(c, arity, s) /* */ int c; /* */ int arity; /* */ String s; /* */ { /* */ EnsureInit; /* */ if ( active[c] ) free_macdef(active[c]); /* */ /* */ active[c] = new_macdef(StringNULL, /* */ arity, /* */ tokenize(s,arity)); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: TeX_reset() ** Purpose: Reset the \TeX{} reading apparatus to its initial ** state. All macros and active characters are cleared ** and the memory is released. Thus this function can ** also be used for this purpose. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void TeX_reset() /* */ { int i; /* */ MacDef md, next; /* */ /* */ for (i = 0; i < 256; i++) /* */ { free_macdef(active[i]); } /* */ /* */ md = macro; /* */ macro = MacDefNULL; /* */ while ( md ) /* */ { next = NextMacro(md); /* */ free_macdef(md); /* */ md = next; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: get_EOF() ** Purpose: ** Arguments: ** ** Returns: **___________________________________________________ */ static int get_EOF() /* */ { return EOF; /* */ } /*------------------------*/ static FILE *src_file; /* */ static String src_string; /* */ static String src_ptr; /* */ static int (*src_get)() = get_EOF; /* */ /*----------------------------------------------------------------------------- ** Function: get_string() ** Purpose: ** ** ** Arguments: ** ** Returns: **___________________________________________________ */ static int get_string() /* */ { return ( *src_ptr ? *(src_ptr++) : EOF ); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: get_file() ** Purpose: ** ** ** Arguments: ** ** Returns: **___________________________________________________ */ static int get_file() /* */ { return getc(src_file); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: TeX_open_file() ** Purpose: Prepare things to parse from a file. ** Arguments: ** file File pointer of the file to read from. ** Returns: nothing **___________________________________________________ */ void TeX_open_file(file) /* */ FILE * file; /* */ { src_file = file; /* */ src_get = get_file; /* */ tex_clear; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: TeX_open_string() ** Purpose: Prepare things to parse from a string. ** Arguments: ** s String to read from. ** Returns: nothing **___________________________________________________ */ void TeX_open_string(s) /* */ String s; /* */ { src_ptr = src_string = s; /* */ src_get = get_string; /* */ tex_clear; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: TeX_close() ** Purpose: Gracefully terminate the reading of \TeX{} tokens. Any ** remaining pieces of text which have already been ** consumed are discarted. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void TeX_close() /* */ { Uchar c; /* */ String s; /* */ src_get = get_EOF; /* */ while ( TeX_read(&c, &s) ) ; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: fill_token() ** Purpose: Check if *tp contains a token. ** Otherwise try to get one and store it there. ** Arguments: ** tp the pointer to the token ** Returns: **___________________________________________________ */ static int fill_token(tp) /* */ register Token *tp; /* */ { /* */ if ( *tp == TokenNULL /* */ && (*tp=TeX_get_token(src_get)) == TokenNULL )/* */ { return 0; } /* */ return 1; /* */ } /*------------------------*/ #define UnlinkToken(T,T2) T2 = T; T = NextToken(T) #define UnlinkAndFreeToken(T,T2) UnlinkToken(T,T2); free_1_token(T2) /*----------------------------------------------------------------------------- ** Function: TeX_read() ** Purpose: Read a single Token and return it as a pair consisting ** of an ASCII code and possibly a string in case of a ** macro token. ** Arguments: ** cp Pointer to position where the character is stored. ** sp Pointer to position where the string is stored. ** Returns: |FALSE| iff everything went right. **___________________________________________________ */ int TeX_read(cp, sp) /* */ String cp; /* */ String *sp; /* */ { static Token t = TokenNULL; /* */ static Token old_t = TokenNULL; /* */ static Token arg[10]; /* */ Token t2, tp; /* */ int i, d; /* */ /* */ EnsureInit; /* */ if ( old_t != TokenNULL ) free_1_token(old_t); /* */ /* */ while ( fill_token(&t) ) /* One token left or */ { /* I got a new one. */ MacDef mac = active[TokenChar(t)]; /* */ if ( mac != MacDefNULL ) /* Is it active? */ { UnlinkAndFreeToken(t, t2); /* Delete active token */ } /* */ else if ( TokenChar(t) == CHAR_ESCAPE && /* */ (mac=find_macro(TokenSeq(t),macro)) /* or an undefined */ != MacDefNULL ) /* */ { UnlinkAndFreeToken(t,t2); /* Delete macro name token*/ while ( fill_token(&t) /* While there are more */ && TokenChar(t) == CHAR_SPACE) /* tokens and == ' ' */ { UnlinkAndFreeToken(t,t2); } /* unlink space */ } /* */ else /* */ { *cp = TokenChar(t); /* */ *sp = TokenSeq(t); /* */ UnlinkToken(t,old_t); /* */ return 1; /* */ } /* */ /* */ for (i = 1; i <= MacroArity(mac); ++i) /* Fill the argument */ { /* vector */ if ( !fill_token(&t) ) /* */ { arg[i] = TokenNULL; /* Not enough tokens */ Err("*** Unexpected EOF\n"); /* */ } /* */ else if (TokenChar(t) == CHAR_BEG_GROUP) /* If there is a group */ { tp = t; /* */ d = 0; /* */ while ( fill_token(&NextToken(tp)) && /* While there are more */ (TokenChar(NextToken(tp)) /* tokens */ != CHAR_END_GROUP /* and */ || d != 0 ) ) /* no matching '}' */ { tp = NextToken(tp); /* walk ahead and */ switch ( TokenChar(tp) ) /* count braces */ { case CHAR_BEG_GROUP: ++d; break; /* */ case CHAR_END_GROUP: d--; break; /* */ } /* */ } /* */ t2 = NextToken(NextToken(tp)); /* */ free_1_token(NextToken(tp)); /* remove final '}' */ NextToken(tp) = TokenNULL; /* */ tp = t; t = t2; /* */ UnlinkAndFreeToken(tp,t2); /* remove initial '{' */ arg[i] = tp; /* */ } /* */ else /* */ { arg[i] = t; /* Move one token */ t = NextToken(t); /* to argument vector */ NextToken(arg[i]) = TokenNULL; /* */ } /* */ } /* */ /* */ t = token_list_copy(MacroToken(mac),t,arg); /* */ /* */ for (i = 1; i < MacroArity(mac); ++i) /* free the arg vector */ { if ( arg[i] != TokenNULL ) /* */ { free_tokens(arg[i]); /* */ arg[i] = TokenNULL; /* */ } /* */ } /* */ } /* */ old_t = TokenNULL; /* */ return 0; /* */ } /*------------------------*/ /*****************************************************************************/ /*** Stand alone version ***/ /*****************************************************************************/ #ifdef STANDALONE /*----------------------------------------------------------------------------- ** Function*: new_string() ** Purpose: ** ** ** Arguments: ** s ** Returns: **___________________________________________________ */ static char * new_string(s) /* */ register char * s; /* */ { register char * t; /* */ if ( (t=malloc(strlen(s)+1)) == NULL ) /* */ { OUT_OF_MEMORY("string"); } /* */ (void)strcpy(t,s); return(t); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function*: main() ** Purpose: Main routine for the stand alone version. ** Arguments: ** argc Number of arguments (+1) ** argv Array of command line arguments (and program name) ** Returns: **___________________________________________________ */ int main(argc,argv) /* */ int argc; /* */ char *argv[]; /* */ { FILE *file; /* */ int kept = 0; /* */ char buffer[1024]; /* */ char c; /* */ char *s; /* */ /* */ /* */ if ( argc > 3 ) /* */ { Err("\nTeX macro expander. gene 1/95\n\n"); Err("Usage: tex_read [macro_file [input_file]]\n\n"); Err("\tRead the macros and expand them in the input file\n"); Err("\tafterwards. Comments are also eliminated.\n\n"); Err("\tThe macros are made up of lines of the following form:\n"); Err("\t\tmacname[args]=replacement text\n"); Err("\twhere 0<=args<=9. If args=0 then [0] can be omitted.\n"); Err("\treplacement text may also contain macros which are expanded.\n\n"); Err("\tThe program mimics the reading mechanism of TeX.\n"); Err("\t\n"); return; /* */ } /* */ if ( argc > 1 ) /* */ { if ( (file = fopen(argv[1],"r")) == NULL ) /* */ { ERROR_EXIT("File open error"); } /* */ while ( fgets(buffer,1024,file) ) /* */ { for(s=buffer;*s;++s) if(*s=='\n') *s = '\0'; /* */ for(s=buffer;*s&&isspace(*s);++s) ; /* */ if ( *s == '\\' ) TeX_def(s); /* */ } /* */ TeX_close(); /* */ (void)fclose(file); /* */ } /* */ file = stdin; /* */ if ( argc > 2 && /* */ (file = fopen(argv[2],"r")) == NULL ) /* */ { ERROR_EXIT("File open error"); } /* */ /* */ TeX_open_file(file); /* */ /* */ while ( TeX_read(&c,&s) ) /* */ { if ( kept ) /* */ { if ( isalpha(c) ) (void)putchar(' '); /* */ kept = 0; /* */ } /* */ (void)putchar(c); /* */ if ( s ) /* */ { (void)fputs(s,stdout); /* */ kept = isalpha(*s); /* */ } /* */ } /* */ /* */ TeX_close(); /* */ /* */ if ( file != stdin ) (void)fclose(file); /* */ return 0; /* */ } /*------------------------*/ #endif /*STANDALONE*/ #ifdef DEBUG /*----------------------------------------------------------------------------- ** Function: show_tokens() ** Purpose: ** ** ** Arguments: ** t ** Returns: nothing **___________________________________________________ */ static void show_tokens(t) /* */ register Token t; /* */ { /* */ while ( t != TokenNULL ) /* */ { if ( TokenChar(t) == CHAR_ESCAPE ) /* */ { (void)printf("_\\%s",TokenSeq(t)); } /* */ else if ( TokenChar(t) > 0xff ) /* */ { (void)printf("_#%d",TokenChar(t)>>8); /* */ } /* */ else /* */ { (void)printf("_%c",TokenChar(t)); } /* */ t = NextToken(t); /* */ } /* */ } /*------------------------*/ #endif /*DEBUG*/ BibTool/type.c0000644000175100017510000001335512646457731012203 0ustar genegene/*** type.c ******************************************************************* ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** ** Description: ** This file contains functions to support a separate treatment of ** character types. The normal functions and macros in |ctype.h| are ** replaced by those in |type.h|. This file contains an initialization ** function which is required for the macros in |type.h| to work ** properly. ** ** See also the documentation of the header file |type.h| for ** further information. ** ******************************************************************************/ /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #define INIT_TYPE #include /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ #define to_lower(C) ((C) + 'a'-'A') #define to_upper(C) ((C) + 'A'-'a') /*----------------------------------------------------------------------------- ** Function: init_type() ** Purpose: This is the initialization routine for this file. This ** has to be called before some of the macros in |type.h| ** will work as described. It does no harm to call this ** initialization more than once. It just takes some time. ** ** Note that this function is for internal purposes ** only. The normal user should call |init_bibtool()| ** instead. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void init_type() /* */ { register int i; /* */ /* */ for ( i = 0; i < 256; ++i ) /* */ { trans_lower[i] = is_upper(i)?to_lower(i):i; /* */ trans_upper[i] = is_lower(i)?to_upper(i):i; /* */ trans_id[i] = i; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: add_word_sep() ** Type: void ** Purpose: ** Mark some characters as word separator. ** Arguments: ** s the allowed word separator characters ** Returns: nothing **___________________________________________________ */ void add_word_sep(s) /* */ register String s; /* */ { /* */ if ( s == StringNULL ) return; /* */ for ( ; *s ; s++ ) /* */ { type__allowed[*s] |= T__WordSep; } /* */ } /*------------------------*/ #ifdef DEBUG #include #endif /*----------------------------------------------------------------------------- ** Function: case_cmp() ** Purpose: Compare two strings ignoring cases. If the strings are ** identical up to differences in case then this function ** returns |TRUE|. ** Arguments: ** s First string to consider. ** t Second string to consider. ** Returns: |FALSE| iff the strings differ. **___________________________________________________ */ int case_cmp(s, t) /* */ register String s; /* */ register String t; /* */ { /* */ #ifdef DEBUG assert(s!=NULL); /* */ assert(t!=NULL); /* */ #endif while ( *s ) /* */ { if ( ToLower(*(s++)) != ToLower(*(t++)) ) /* */ return 0; /* */ } /* */ #ifdef DEBUG assert(t!=NULL); /* */ #endif return (*t=='\0'?1:0); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: lower() ** Purpose: Function to translate all letters in a string to lower case. ** Arguments: ** s string to convert ** Returns: The converted string. **___________________________________________________ */ String lower(s) /* */ register String s; /* */ { String t = s; /* */ while ( *s ) { *s = ToLower(*s); ++s; } /* */ return t; /* */ } /*------------------------*/ BibTool/version.c0000644000175100017510000000500412646463517012676 0ustar genegene/*** version.c **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include /*----------------------------------------------------------------------------- ** Variable: bibtool_version ** Type: char * ** Purpose: This string variable contains the version number of ** \BibTool. Usually it is of the form ** \textit{major.minor} where \textit{major} and ** \textit{minor} are the major and minor version ** numbers. In addition a post-fix like |alpha| or a ** patch level like |p1| can be present. **___________________________________________________ */ char * bibtool_version = "2.63"; /* */ /*----------------------------------------------------------------------------- ** Variable: bibtool_year ** Type: char * ** Purpose: This string variable contains the publication year for this ** version. **___________________________________________________ */ char * bibtool_year = "2016"; /* */ /*----------------------------------------------------------------------------- ** Function: show_version() ** Purpose: Print the version number and a short copyright notice ** onto the error stream. ** Arguments: none ** Returns: nothing **___________________________________________________ */ void show_version() /* */ { /* */ ErrPrintF2("BibTool Vers. %s (C) 1996-%s Gerd Neugebauer\n\n",/* */ bibtool_version, bibtool_year); /* */ } /*------------------------*/ BibTool/wordlist.c0000644000175100017510000002103512646457746013071 0ustar genegene/*** wordlist.c *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions which deal with lists of ** words. Those words are in fact simple strings. Thus this ** module provides a very general functionality, namely a list of ** strings and the associated methods. ** ******************************************************************************/ #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: add_word() ** Purpose: Put a string into a word list. The string itself is ** \emph{not} copied. Thus it is highly recommended to ** use symbols as words nevertheless this is not ** required as long as the string |s| persists as long as ** the word list exists. ** ** The second argument is a pointer to a |WordList|. This ** destination is modified by adding a new node. The use ** of a pointer allows a uniform treatment of empty and ** not empty word lists. ** ** If no memory is left then an error is raised and the program ** is terminated. ** Arguments: ** s String to add to the wordlist. ** wlp Pointer to a wordlist. ** Returns: nothing **___________________________________________________ */ void add_word(s,wlp) /* */ register String s; /* */ register WordList *wlp; /* */ { register WordList wl; /* */ register int cmp = 1; /* */ /* */ while ( *wlp != WordNULL /* */ && (cmp=strcmp((char*)ThisWord(*wlp), /* */ (char*)s)) < 0 ) /* */ { wlp = & NextWord(*wlp); } /* */ /* */ if ( cmp == 0 ) return; /* */ /* */ if ( (wl=(WordList)malloc(sizeof(SWordList))) == WordNULL )/* */ { OUT_OF_MEMORY("WordList"); } /* */ /* */ ThisWord(wl) = s; /* */ NextWord(wl) = *wlp; /* */ *wlp = wl; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: delete_word() ** Purpose: Remove a word from a |WordList|. Only the first ** appearance of such a word is removed. I a word is ** found which contains the same string as |s| then the ** associated node is removed from the list and the ** function |fct| is called to free the memory of the ** string in the |WordList| node if the function is not ** |NULL|. In this case the function returns ** |0|. Otherwise |1| is returned. ** Arguments: ** s Word to remove. ** wlp Pointer to the word list to modify. ** fct Function to call to free the memory occupied by the word. ** Returns: |0| if the word was not found. |1| otherwise. **___________________________________________________ */ int delete_word(s, wlp, fct) /* */ String s; /* */ WordList *wlp; /* */ void (*fct)_ARG((String)); /* */ { WordList wl; /* */ int cmp = 1; /* */ while ( *wlp != WordNULL /* */ && (cmp=strcmp((char*)ThisWord(*wlp), /* */ (char*)s)) < 0 ) /* */ { wlp = & NextWord(*wlp); } /* */ /* */ if ( cmp == 0 ) return 0; /* */ /* */ wl = *wlp; /* */ *wlp = NextWord(wl); /* */ if ( fct != NULL ) { (*fct)(ThisWord(wl)); } /* */ free(wl); /* */ return 1; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: free_words() ** Purpose: Release the memory allocated for a list of words. ** All nodes in the list are freed. The function |fct| is ** called to free the memory occupied by the string ** component if it is not |NULL|. ** Arguments: ** wlp Pointer to the |WordList|. ** fct Function to be called to free the memory of the word itself. ** If it is |NULL| then no function is called. ** Returns: nothing **___________________________________________________ */ void free_words(wlp, fct) /* */ WordList *wlp; /* */ void (*fct)_ARG((String)); /* */ { WordList wl, next; /* */ /* */ wl = *wlp; /* */ *wlp = WordNULL; /* */ while ( wl ) /* */ { next = NextWord(wl); /* */ if ( fct != NULL ) { (*fct)(ThisWord(wl)); } /* */ (void)free(wl); /* */ wl = next; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: foreach_word() ** Purpose: Applies the given function |fct| to all elements in ** the |WordList| as long as the function does not return ** 0. Thus it can be used to search for a specified word ** -- e.g. determined by matching against a ** template. Another application the the processing of ** all elements in the |WordList|. In this case |fct| ** must always return |TRUE|. ** Arguments: ** wl WordList to traverse. ** fct function to apply. ** Returns: return value of last function or 1. **___________________________________________________ */ int foreach_word(wl, fct) /* */ WordList wl; /* */ int (*fct)_ARG((String)); /* */ { int ret = 1; /* */ while ( wl && (ret=(fct)(ThisWord(wl))) ) /* */ { wl = NextWord(wl); } /* */ return ret; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: find_word() ** Purpose: Look up a word in a word list. The comparison is done ** case insensitive. ** Arguments: ** s String to find. ** wl Word list to search in. ** Returns: |FALSE| iff the word does not occur in the word list. **___________________________________________________ */ int find_word(s, wl) /* */ register String s; /* */ register WordList wl; /* */ { /* */ while ( wl != WordNULL ) /* */ { /* */ if ( case_cmp(ThisWord(wl),s) ) /* */ { return 1; } /* */ wl = NextWord(wl); /* */ } /* */ /* */ return 0; /* */ } /*------------------------*/ BibTool/config.h0000644000175100017510000002030312646457055012462 0ustar genegene/*** config.h ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ /****************************************************************************** ** Configuration Section ******************************************************************************/ /*----------------------------------------------------------------------------- ** Define the default value of the resource search path. ** This is a string containing a colon/semicolon/comma separated list of ** directories. ** DON'T FORGET THE CURRENT DIRECTORY. ** To clear it set it to NULL. ** This can also be specified in the Makefile. This value is used if no ** Makefile is used or the macro is not set in the makefile. */ #ifndef RSC_BIBTOOL_DEFAULT #define RSC_BIBTOOL_DEFAULT NULL #endif /*----------------------------------------------------------------------------- ** If the following macro is defined then the standard @types are provided ** automatically. ** The value is a comma separated list of strings. ** Note that COMMENT, PREAMBLE, STRING, ALIAS, MODIFY, and INCLUDE ** are hard wired and need not to be in this list! */ #define INITIALIZE_BIBTEX_ENTRIES \ "Article" ,"Book" ,"Booklet" ,"Conference" ,\ "InBook" ,"InCollection" ,"InProceedings","Manual" ,\ "MastersThesis" ,"Misc" ,"PhDThesis" ,"Proceedings" ,\ "TechReport" ,"Unpublished" /*----------------------------------------------------------------------------- ** If the following macro is defined then the listed macros are predefined. ** The value is a comma separated list of strings. */ #define INITIALIZE_MACROS \ "jan", "feb", "mar", "apr", "may", "jun", \ "jul", "aug", "sep", "oct", "nov", "dec" /*----------------------------------------------------------------------------- ** If the following macro is defined then ignored words are initialized. ** Those words anre not taken into account when sorting or key generation ** for titles is performed. ** The value is a comma separated list of strings. */ #define INITIALIZE_IGNORED_WORDS \ "a", "an", "the", \ "der", "die", "das", "ein", "eine", \ "einen", "eines", "einer", "einem", \ "le", "les", "la", "un", "une", \ "el", "il" /*----------------------------------------------------------------------------- ** Define the default value of the BibTeX search path. ** This is a string containing a colon separated list of directories. ** DON'T FORGET THE CURRENT DIRECTORY. ** To clear it set it to NULL. ** This can also be specified in the Makefile. This value is used if no ** Makefile is used or the macro is not set in the makefile. */ #ifndef RSC_BIBINPUTS_DEFAULT #define RSC_BIBINPUTS_DEFAULT NULL #endif /*----------------------------------------------------------------------------- ** Define the name of an environment variable of the BibTeX search path. ** Consult your local guide on the environment variable used. ** Be careful and strip the ninth character if only eight are allowed. */ #define RSC_BIBINPUTS "BIBINPUTS" /*----------------------------------------------------------------------------- ** Define the name of the default resource file name. ** On MSDOS-like maschines I recommend "bibtool.rsc" */ #ifdef MSDOS #define DefaultResourceFile "bibtool.rsc" #else #define DefaultResourceFile ".bibtoolrsc" #endif /*----------------------------------------------------------------------------- ** Define the name of an environment variable containing a resource file name. ** Undefine this macro if no such feature is present in your system. */ #define RSC_ENV_VAR "BIBTOOLRSC" /*----------------------------------------------------------------------------- ** Define the name of an environment variable of the resource search path. ** Undefine this macro if no such feature is present in your system. */ #define RSC_BIBTOOL "BIBTOOL" /*----------------------------------------------------------------------------- ** This character separates the directories in environment search paths. ** This is also done in the makefile. Do not define it here if you use the ** makefile. ** On UN*X systems it should be ":". ** On MSDOS and Atari I recommend ";". ** On Amiga I recommend ",". */ #ifndef ENV_SEP #ifdef MSDOS #define ENV_SEP ";" #else #ifdef AMIGA #define ENV_SEP "," #else #define ENV_SEP ":" #endif #endif #endif /*----------------------------------------------------------------------------- ** Define the name of an environment variable containing the home directory. ** This implies a UN*X-like file system. ** Undefine this macro if no such feature is present in your system. */ #define HOME_ENV_VAR "HOME" /*----------------------------------------------------------------------------- ** This character separates directory and file components of a complete file ** name. ** This is also defined in the makefile. Do not define it here if you use the ** makefile. ** On UN*X systems it should be "/". ** On M$DOS-like systems it should be "\\". */ #ifndef DIR_SEP #ifdef MSDOS #define DIR_SEP "\\" #else #define DIR_SEP "/" #endif #endif /*----------------------------------------------------------------------------- ** This character starts options on the command line. ** On UN*X systems it should be '-' */ #define OptionLeadingCharacter '-' /*----------------------------------------------------------------------------- ** Maximal number of user defined formats. ** At least 2 are required by BibTool! */ #define NUMBER_OF_FORMATS 128 /*----------------------------------------------------------------------------- ** Size of the hash table. ** This should be a prime number. Don't use a value which is too small. ** 307 is just ok if you consider databases with up to 100 entries. ** 1021 is for larger databases. */ #define HASH_TABLE_SIZE 1021 /*----------------------------------------------------------------------------- ** Define the next macro to enable output of the symbol table. ** Mainly interesting for debugging (i.e. not for you:-). */ /* #define SYMBOL_DUMP */ #ifdef MSDOS /*----------------------------------------------------------------------------- ** The following section contains (some) support for M*DOS like computers. ** They only are in effect when the macro MSDOS is defined. ** Don't blame me, I do not use such such a kind of "OS" **----------------------------------------------------------------------------- */ /*----------------------------------------------------------------------------- ** Define the following macro to enable emtex like search path initalization. */ #define EMTEX_LIKE_PATH /*----------------------------------------------------------------------------- ** The following macro holds the environment variable containing the path. */ #define EMTEXDIR "EMTEXDIR" /*----------------------------------------------------------------------------- ** The following macro holds the default if no environment variable is found. */ #define EMTEXTDIR_DEFAULT "\\emtex" /*----------------------------------------------------------------------------- ** The following macro holds the subdir of EMTEXDIR for bibtex. */ #define EMTEXT_BIBTEX "\\bibtex\\bib" /*----------------------------------------------------------------------------- ** The following macro holds the subdir of EMTEXDIR for bibtool. */ #define EMTEXT_RESOURCE "\\bibtool" #endif BibTool/include/bibtool/crossref.h0000644000175100017510000000270212646460272016116 0ustar genegene/*** crossref.h *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 2007-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file makes available the function defined in ** |crossref.c|. This file includes the header files |database.h| and ** |record.h|. ******************************************************************************/ #include #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int expand_crossref _ARG((DB db,Record rec)); BibTool/include/bibtool/database.h0000644000175100017510000001561012646460277016043 0ustar genegene/*** database.h *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file contains functions which deal with databases. ** ** This header file provides also access to the functions and ** variables defined in |database.c|. Consult the documentation ** of this file for details. ** ** This header file automatically includes || and ** |record.h| aswell. ** ******************************************************************************/ #ifndef DATABASE_H #define DATABASE_H #include #include /*----------------------------------------------------------------------------- ** Typedef: DB ** Purpose: This is a pointer type referencing a \BibTeX{} ** database. It contains all information which ** characterizes a database. ** ** The members of this record should not be used ** explicitly. Instead the macros should be used which ** are provided to accss this data type. ** **___________________________________________________ */ typedef struct /* */ { Record db_normal; /* List of normal records.*/ Record db_string; /* List of local macros. */ Record db_preamble; /* List of additional */ /* \TeX{} code. */ Record db_comment; /* List of trailing */ /* comments which are */ /* not attached to */ /* records. */ Record db_modify; /* List of modification */ /* rules. */ Record db_include; /* List of included files.*/ Record db_alias; /* List of aliases. */ } sDB, *DB; /* */ /*----------------------------------------------------------------------------- ** Constant: NoDB() ** Type: DB ** Purpose: This is an invalid database. In fact it is |NULL| of ** the type |DB|. **___________________________________________________ */ #define NoDB ((DB)0) /*----------------------------------------------------------------------------- ** Macro: DBnormal() ** Type: Record ** Purpose: This is the functional representation of the normal ** component of a database. It can be used to extract ** this information. It can also be used as a lvalue. ** Arguments: ** DB The database to consider. **___________________________________________________ */ #define DBnormal(DB) ((DB)->db_normal) /*----------------------------------------------------------------------------- ** Macro: DBstring() ** Type: Record ** Purpose: This is the functional representation of the string ** component of a database. It can be used to extract ** this information. It can also be used as a lvalue. ** Arguments: ** DB The database to consider. **___________________________________________________ */ #define DBstring(DB) ((DB)->db_string) /*----------------------------------------------------------------------------- ** Macro: DBpreamble() ** Type: Record ** Purpose: This is the functional representation of the preamble ** component of a database. It can be used to extract ** this information. It can also be used as a lvalue. ** Arguments: ** DB The database to consider. **___________________________________________________ */ #define DBpreamble(DB) ((DB)->db_preamble) /*----------------------------------------------------------------------------- ** Macro: DBcomment() ** Type: Record ** Purpose: This is the functional representation of the comment ** component of a database. It can be used to extract ** this information. It can also be used as a lvalue. ** Arguments: ** DB The database to consider. **___________________________________________________ */ #define DBcomment(DB) ((DB)->db_comment) /*----------------------------------------------------------------------------- ** Macro: DBalias() ** Type: Record ** Purpose: This is the functional representation of the alias ** component of a database. It can be used to extract ** this information. It can also be used as a lvalue. ** Arguments: ** DB The database to consider. **___________________________________________________ */ #define DBalias(DB) ((DB)->db_alias) /*----------------------------------------------------------------------------- ** Macro: DBmodify() ** Type: Record ** Purpose: This is the functional representation of the modify ** component of a database. It can be used to extract ** this information. It can also be used as a lvalue. ** Arguments: ** DB The database to consider. **___________________________________________________ */ #define DBmodify(DB) ((DB)->db_modify) /*----------------------------------------------------------------------------- ** Macro: DBinclude() ** Type: Record ** Purpose: This is the functional representation of the include ** component of a database. It can be used to extract ** this information. It can also be used as a lvalue. ** Arguments: ** DB The database to consider. **___________________________________________________ */ #define DBinclude(DB) ((DB)->db_include) /*---------------------------------------------------------------------------*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif DB new_db _ARG((void)); Record db_find _ARG((DB db, String key)); Record db_search _ARG((DB db, String key)); String db_new_key _ARG((DB db, String key)); String db_string _ARG((DB db, String s, int localp)); int *db_count _ARG((DB db,int *lp)); int read_db _ARG((DB db,String file, int verbose)); void db_insert _ARG((DB db,Record rec, int verbose)); void db_forall _ARG((DB db,int (*fct)_ARG((DB, Record)))); void db_mac_sort _ARG((DB db)); void db_rewind _ARG((DB db)); void db_sort _ARG((DB db,int (*less)_ARG((Record, Record)))); void db_xref_undelete _ARG((DB db)); void delete_record _ARG((DB db, Record rec)); void free_db _ARG((DB db)); void print_db _ARG((FILE *file, DB db, char *spec)); /*---------------------------------------------------------------------------*/ #endif BibTool/include/bibtool/bibtool.h0000644000175100017510000000434512646460263015727 0ustar genegene/*** bibtool.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file contains includes for all other header files ** belonging to the \BibTool{} C library. It is here for the ** convenience of the C programmer who does not have to include ** two dozen header files but can use this single file. Thus any ** C program which utilizes the \BibTool{} C library can start as ** follows: ** ** \verb|#include | ** ** Note that this include file also contains includes to system ** specific header files. They are determined during configuration. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include BibTool/include/bibtool/entry.h0000644000175100017510000001543512646460304015434 0ustar genegene/*** entry.h ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** ** This module provides also access to the functions and ** variables defined in |entry.c|. Consult also the documentation ** of this file for details. ** ** This header file automatically includes |symbols.h|. ** ******************************************************************************/ #include /*----------------------------------------------------------------------------- ** Variable: entry_type ** Type: String * ** Purpose: This is an array of strings which represent entry ** types. They are either built-in or user defined. Use ** the function |def_entry_type()| to allocate a new ** entry type and the function |get_entry_type()| to find ** a certain entry type. **___________________________________________________ */ extern String *entry_type; /*----------------------------------------------------------------------------- ** Macro: EntryName() ** Type: String ** Purpose: This is the functional representation of the name ** component for an entry type. The argument is the index ** of an entry type. This macro can also be used as ** lvalue. No range checks are performed. ** Arguments: ** Entry Index of the entry. **___________________________________________________ */ #define EntryName(Entry) entry_type[Entry] /*----------------------------------------------------------------------------- ** Constant: BIB_EOF ** Type: int ** Purpose: This symbolic constant is returned when a record has ** to be read and the end of file has been ** encountered. It is some negative value for which no ** entry type is defined. **___________________________________________________ */ #define BIB_EOF -2 /*----------------------------------------------------------------------------- ** Constant: BIB_NOOP ** Type: int ** Purpose: This symbolic constant is returned when a record has ** to be read and something has been encountered which ** should be ignored. It is some negative value for which no ** entry type is defined. **___________________________________________________ */ #define BIB_NOOP -1 /*----------------------------------------------------------------------------- ** Constant: BIB_STRING ** Type: int ** Purpose: This symbolic constant representing a record type of a ** \BibTeX{} macro (|@String|). This is a special record ** type which is provided automatically. **___________________________________________________ */ #define BIB_STRING 0 /*----------------------------------------------------------------------------- ** Constant: BIB_PREAMBLE ** Type: int ** Purpose: This symbolic constant representing a record type of a ** \BibTeX{} preamble (|@Preamble|). This is a special record ** type which is provided automatically. **___________________________________________________ */ #define BIB_PREAMBLE 1 /*----------------------------------------------------------------------------- ** Constant: BIB_COMMENT ** Type: int ** Purpose: This symbolic constant representing a record type of a ** \BibTeX{} comment (|@Comment|). This is a special record ** type which is provided automatically. **___________________________________________________ */ #define BIB_COMMENT 2 /*----------------------------------------------------------------------------- ** Constant: BIB_ALIAS ** Type: int ** Purpose: This symbolic constant representing a record type of a ** \BibTeX{} alias (|@Alias|) which is proposed for ** \BibTeX\,1.0. This is a special record type which is ** provided automatically. **___________________________________________________ */ #define BIB_ALIAS 3 /*----------------------------------------------------------------------------- ** Constant: BIB_MODIFY ** Type: int ** Purpose: This symbolic constant representing a record type of a ** \BibTeX{} modification rule (|@Modify|) which is proposed for ** \BibTeX\,1.0. This is a special record type which is ** provided automatically. **___________________________________________________ */ #define BIB_MODIFY 4 /*----------------------------------------------------------------------------- ** Constant: BIB_INCLUDE ** Type: int ** Purpose: This symbolic constant representing a record type of a ** \BibTeX{} inclusion instruction (|@Include|) which is ** proposed for \BibTeX\,1.0. This is a special record ** type which is provided automatically **___________________________________________________ */ #define BIB_INCLUDE 5 /*----------------------------------------------------------------------------- ** Macro: IsSpecialRecord() ** Purpose: Test whether a given record type denotes a special record. ** Special records are those defined above. They are ** provided automatically since \BibTeX{} is supposed to ** do so as well. ** Arguments: ** Type Record type which should be checked. ** Returns: |TRUE| iff the rcord type denoted a special record. **___________________________________________________ */ #define IsSpecialRecord(Type) ( Type <= 5 ) /*----------------------------------------------------------------------------- ** Macro: IsNormalRecord() ** Purpose: Test whether a given record is a normal record. A ** normal record is one defined by a user. Normal records ** have indices larger than those of special records. ** Arguments: ** Type Record type which should be checked. ** Returns: |TRUE| iff the rcord type denoted a normal record. **___________________________________________________ */ #define IsNormalRecord(Type) ( Type > 5 ) #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String get_entry_type _ARG((int i)); /* entry.c */ int find_entry_type _ARG((String s)); /* entry.c */ void def_entry_type _ARG((String s)); /* entry.c */ void init_entries _ARG((void)); /* entry.c */ BibTool/include/bibtool/error.h0000644000175100017510000004002412646460310015411 0ustar genegene/*** error.h ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file provides means for issuing error ** messages. Most of the macros provided in this header file are ** based on the function |error()| described in |error.c|. ** Nevertheless this function covers the general cases the macros ** in this header file are more convenient since they hide the ** unneccesary arguments of the |error()| function providing ** appropriate values. ** ** This header file makes availlable the function |error()| as ** defined in |error.c|. ** ******************************************************************************/ #include #include /*----------------------------------------------------------------------------- ** Constant: ERR_ERROR ** Type: int ** Purpose: Error type: Indicate that the error can not be ** suppressed and the messaged is marked as error. **___________________________________________________ */ #define ERR_ERROR 1 /*----------------------------------------------------------------------------- ** Constant: ERR_WARNING ** Type: int ** Purpose: Error type: Indicate that the error is in fact a ** warning which can be suppressed. The messaged is ** marked as warning. This flag is only in effect if the ** |ERR_ERROR| flag is not set. **___________________________________________________ */ #define ERR_WARNING 2 #define ERR_WARN 2 /*----------------------------------------------------------------------------- ** Constant: ERR_POINT ** Type: int ** Purpose: Error type: Indicate that the line and the error ** pointer should be displayed (if not suppressed via ** other flags). **___________________________________________________ */ #define ERR_POINT 4 /*----------------------------------------------------------------------------- ** Constant: ERR_FILE ** Type: int ** Purpose: Error type: Indicate that the file name and line ** number should be displayed (if not suppressed via ** other flags). **___________________________________________________ */ #define ERR_FILE 8 /*----------------------------------------------------------------------------- ** Constant: ERR_EXIT ** Type: int ** Purpose: Error type: Indicate that the |error()| function ** should be terminated by |exit()| instead of ** returning. **___________________________________________________ */ #define ERR_EXIT 256 extern char *err_format; extern String err_point; extern String err_oom; extern FILE *err_file; /*----------------------------------------------------------------------------- ** Macro: ERROR_EXIT() ** Type: void ** Purpose: Raise an error, print the single string argument as ** error message and terminate the program with |exit()|. ** Arguments: ** X Error message. ** Returns: nothing **___________________________________________________ */ #define ERROR_EXIT(X) \ error(ERR_ERROR|ERR_EXIT,(String)X, \ (String)0,(String)0,(String)0,(String)0,0,(char*)0) /*----------------------------------------------------------------------------- ** Macro: OUT_OF_MEMORY() ** Type: void ** Purpose: Raise an error because |malloc()| or |realloc()| ** failed. The argument denoted the type of memory for ** which the allocation failed. The program is ** terminated. ** Arguments: ** X String denoting the type of unallocatable memory. ** Returns: nothing **___________________________________________________ */ #define OUT_OF_MEMORY(X) \ error(ERR_ERROR|ERR_EXIT,err_oom, \ (String)X,err_point,(String)0,(String)0,0,(char*)0) /*----------------------------------------------------------------------------- ** Macro: ERROR() ** Type: void ** Purpose: Raise an error. Print the argument as error message ** and continue. ** Arguments: ** X Error message. ** Returns: nothing **___________________________________________________ */ #define ERROR(X) \ error(ERR_ERROR,(String)X, \ (String)0,(String)0,(String)0,(String)0,0,(char*)0) /*----------------------------------------------------------------------------- ** Macro: ERROR2() ** Type: void ** Purpose: Raise an error. Print the two arguments as error message ** and continue. ** Arguments: ** X First error message. ** Y Continuation of the error message. ** Returns: nothing **___________________________________________________ */ #define ERROR2(X,Y) \ error(ERR_ERROR,(String)X, \ (String)Y,(String)0,(String)0,(String)0,0,(char*)0) /*----------------------------------------------------------------------------- ** Macro: ERROR3() ** Type: void ** Purpose: Raise an error. Print the three arguments as error message ** and continue. ** Arguments: ** X First error message. ** Y Continuation of the error message. ** Z Second continuation of the error message. ** Returns: nothing **___________________________________________________ */ #define ERROR3(X,Y,Z) \ error(ERR_ERROR,(String)X, \ (String)Y,(String)Z,(String)0,(String)0,0,(char*)0) /*----------------------------------------------------------------------------- ** Macro: WARNING() ** Type: void ** Purpose: Raise a warning. Print the argument as warning message ** and continue. ** Arguments: ** X Warning message. ** Returns: nothing **___________________________________________________ */ #define WARNING(X) \ error(ERR_WARN,(String)X, \ (String)0,(String)0,(String)0,(String)0,0,(char*)0) /*----------------------------------------------------------------------------- ** Macro: WARNING2() ** Type: void ** Purpose: Raise a warning. Print the two arguments as warning message ** and continue. ** Arguments: ** X First warning message. ** Y Continuation of warning message. ** Returns: nothing **___________________________________________________ */ #define WARNING2(X,Y) \ error(ERR_WARN,(String)X, \ (String)Y,(String)0,(String)0,(String)0,0,(char*)0) /*----------------------------------------------------------------------------- ** Macro: WARNING3() ** Type: void ** Purpose: Raise a warning. Print the thre arguments as warning message ** and continue. ** Arguments: ** X First warning message. ** Y Continuation of warning message. ** Z Second continuation of warning message. ** Returns: nothing **___________________________________________________ */ #define WARNING3(X,Y,Z) \ error(ERR_WARN,(String)X, \ (String)Y, (String)Z, StringNULL, StringNULL, 0, (char*)0) /*----------------------------------------------------------------------------- ** Macro: Err() ** Type: void ** Purpose: Print a string to the error stream. This message is ** preceded with an indicator. The message is \emph{not} ** automatically terminated by a newline. ** Arguments: ** S String to print. ** Returns: nothing **___________________________________________________ */ #define Err(S) (void)fprintf(err_file,err_format,S) /*----------------------------------------------------------------------------- ** Macro: ErrC() ** Type: void ** Purpose: Print a single character to the error stream. ** Arguments: ** CHAR Character to send to output. ** Returns: nothing **___________________________________________________ */ #define ErrC(CHAR) (void)fputc(CHAR,err_file) /*----------------------------------------------------------------------------- ** Macro: ErrPrint() ** Type: void ** Purpose: Print a string to the error stream. The string is not ** preceded by any indicator not is it automatically ** terminated by a newline. ** Arguments: ** F String to print. ** Returns: nothing **___________________________________________________ */ #define ErrPrint(F) (void)fputs(F,err_file) /*----------------------------------------------------------------------------- ** Macro: ErrPrintF() ** Type: void ** Purpose: Apply a formatting instruction (with |printf()|). This ** macro takes a format string and a second argument ** which is determined by the formatting string. ** Arguments: ** F Format. ** A Argument. ** Returns: nothing **___________________________________________________ */ #define ErrPrintF(F,A) (void)fprintf(err_file,F,A) /*----------------------------------------------------------------------------- ** Macro: ErrPrintF2() ** Type: void ** Purpose: Apply a formatting instruction (with |printf()|). This ** macro takes a format string and two additional arguments ** which are determined by the formatting string. ** Arguments: ** F Format ** A First argument. ** B Second argument. ** Returns: nothing **___________________________________________________ */ #define ErrPrintF2(F,A,B) (void)fprintf(err_file,F,A,B) /*----------------------------------------------------------------------------- ** Macro: ErrPrintF3() ** Type: void ** Purpose: Apply a formatting instruction (with |printf()|). This ** macro takes a format string and three additional arguments ** which are determined by the formatting string. ** Arguments: ** F Format ** A First argument. ** B Second argument. ** C Third argument. ** Returns: nothing **___________________________________________________ */ #define ErrPrintF3(F,A,B,C) (void)fprintf(err_file,F,A,B,C) /*----------------------------------------------------------------------------- ** Constant: FlushErr() ** Type: void ** Purpose: Flush the error stream. This can be useful when single ** characters are written to an error stream which does ** buffering. ** Returns: nothing **___________________________________________________ */ #define FlushErr (void)fflush(err_file) /*----------------------------------------------------------------------------- ** Macro: VerbosePrint1() ** Type: void ** Purpose: Print an informative message to the error stream. ** Arguments: ** A Verbose message. ** Returns: nothing **___________________________________________________ */ #define VerbosePrint1(A) (void)fprintf(err_file,"--- BibTool: %s\n",A) /*----------------------------------------------------------------------------- ** Macro: VerbosePrint2() ** Type: void ** Purpose: Print an informative message consisting of two ** substrings to the error stream. ** Arguments: ** A Verbose message. ** B Continuation of verbose message. ** Returns: nothing **___________________________________________________ */ #define VerbosePrint2(A,B) (void)fprintf(err_file,"--- BibTool: %s%s\n",A,B) /*----------------------------------------------------------------------------- ** Macro: VerbosePrint3() ** Type: void ** Purpose: Print an informative message consisting of three ** substrings to the error stream. ** Arguments: ** A Verbose message. ** B Continuation of verbose message. ** C Second continuation of verbose message. ** Returns: nothing **___________________________________________________ */ #define VerbosePrint3(A,B,C) (void)fprintf(err_file,"--- BibTool: %s%s%s\n",A,B,C) /*----------------------------------------------------------------------------- ** Macro: VerbosePrint4() ** Type: void ** Purpose: Print an informative message consisting of four ** substrings to the error stream. ** Arguments: ** A Verbose message. ** B Continuation of verbose message. ** C Second continuation of verbose message. ** D Third continuation of verbose message. ** Returns: nothing **___________________________________________________ */ #define VerbosePrint4(A,B,C,D) (void)fprintf(err_file,"--- BibTool: %s%s%s%s\n",A,B,C,D) #ifdef DEBUG /*----------------------------------------------------------------------------- ** Macro: DebugPrint1() ** Type: void ** Purpose: This Macro is for debugging purposes. The compilation ** determines whether this macro prints its argument or ** simply ignores it. This is achieved by defining or ** undefining the macro |DEBUG| when compiling. ** Arguments: ** A Debug message. ** Returns: nothing **___________________________________________________ */ #define DebugPrint1(A) (void)fprintf(err_file,"+++ BibTool: %s\n",A) /*----------------------------------------------------------------------------- ** Macro: DebugPrint2() ** Type: void ** Purpose: This Macro is for debugging purposes. The compilation ** determines whether this macro prints its arguments or ** simply ignores them. This is achieved by defining or ** undefining the macro |DEBUG| when compiling. ** Arguments: ** A Debug message. ** B Continuation of the debug message. ** Returns: nothing **___________________________________________________ */ #define DebugPrint2(A,B) (void)fprintf(err_file,"+++ BibTool: %s%s\n",A,B) /*----------------------------------------------------------------------------- ** Macro: DebugPrint3() ** Type: void ** Purpose: ** Purpose: This Macro is for debugging purposes. The compilation ** determines whether this macro prints its arguments or ** simply ignores them. This is achieved by defining or ** undefining the macro |DEBUG| when compiling. ** Arguments:Debug message. ** A Debug message. ** B Continuation of the debug message. ** C Second continuation of the debug message. ** Returns: nothing **___________________________________________________ */ #define DebugPrint3(A,B,C) (void)fprintf(err_file,"+++ BibTool: %s%s%s\n",A,B,C) /*----------------------------------------------------------------------------- ** Macro: DebugPrintF1() ** Type: void ** Purpose: This Macro is for debugging purposes. The compilation ** determines whether this macro prints its argument or ** simply ignores it. This is achieved by defining or ** undefining the macro |DEBUG| when compiling. ** Arguments: ** A Debug message. ** Returns: nothing **___________________________________________________ */ #define DebugPrintF1(A) (void)fprintf(err_file,A) /*----------------------------------------------------------------------------- ** Macro: DebugPrintF2() ** Type: void ** Purpose: This Macro is for debugging purposes. The compilation ** determines whether this macro prints its arguments or ** simply ignores them. This is achieved by defining or ** undefining the macro |DEBUG| when compiling. ** Arguments: ** F The format for the debug message. ** A Debug message. ** Returns: nothing **___________________________________________________ */ #define DebugPrintF2(F,A) (void)fprintf(err_file,F,A) /*----------------------------------------------------------------------------- ** Macro: DebugPrintF3() ** Type: void ** Purpose: ** Purpose: This Macro is for debugging purposes. The compilation ** determines whether this macro prints its arguments or ** simply ignores them. This is achieved by defining or ** undefining the macro |DEBUG| when compiling. ** Arguments:Debug message. ** F The format for the debug message. ** A Debug message. ** B Continuation of the debug message. ** Returns: nothing **___________________________________________________ */ #define DebugPrintF3(F,A,B) (void)fprintf(err_file,F,A,B) #else #define DebugPrint1(A) #define DebugPrint2(A,B) #define DebugPrint3(A,B,C) #define DebugPrintF1(A) #define DebugPrintF2(A,B) #define DebugPrintF3(A,B,C) #endif #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif void error _ARG((int type,String s1,String s2,String s3,String line,String ep,int line_no,char *file_name));/* error.c*/ void init_error _ARG((FILE * file)); BibTool/include/bibtool/expand.h0000644000175100017510000000265612646460315015555 0ustar genegene/*** expand.h ***************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file makes available the function defined in ** |expand.c|. This file includes the header file |database.h|. ******************************************************************************/ #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String expand_rhs _ARG((String s,String pre,String post, DB db));/* expand.c*/ BibTool/include/bibtool/general.h0000644000175100017510000000650712646460322015710 0ustar genegene/*** general.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ /*----------------------------------------------------------------------------- ** **---------------------------------------------------------------------------*/ #include #include #ifdef __STDC__ #include #include #include #ifdef LINT int fputs(char*,FILE*); int fputc(char,FILE*); int fclose(FILE*); int fflush(FILE*); int fprintf(FILE*,char*, ...); int printf(char*, ...); #endif #else #ifdef HAVE_STRING_H #include #else #include #define strchr(A,B) index(A,B) #define strrchr(A,B) rindex(A,B) #endif #ifdef HAVE_STDLIB_H #include #else extern void exit(); extern VoidPTR malloc(); extern VoidPTR realloc(); extern char *getenv(); #ifdef SIZE_T #define size_t SIZE_T #else #define size_t unsigned #endif #endif #endif /*----------------------------------------------------------------------------- ** Misc definitions **---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Constant: TRUE ** Type: int ** Purpose: Just in case that this constant is not defined in any ** used system header file it will be defined here. It ** represents the |TRUE| condition. **___________________________________________________ */ #ifndef TRUE #define TRUE (1) #endif /*----------------------------------------------------------------------------- ** Constant: FALSE ** Type: int ** Purpose: Just in case that this constant is not defined in any ** used system header file it will be defined here. It ** represents the |FALSE| condition. **___________________________________________________ */ #ifndef FALSE #define FALSE (0) #endif /*----------------------------------------------------------------------------- ** Macro: FOREVER ** Purpose: This is an infinite loop. ** ** Arguments: none **___________________________________________________ */ #define FOREVER for (;;) /*----------------------------------------------------------------------------- ** Macro: POSSIBLY_UNUSED ** Purpose: Mark a variable as possibly unused. It silences a gcc ** compiler warning. ** ** Arguments: none **___________________________________________________ */ #define POSSIBLY_UNUSED(X) (void)(X) BibTool/include/bibtool/init.h0000644000175100017510000000300012646460332015220 0ustar genegene/*** init.h ******************************************************************* ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file provides the prototype for the global initialization ** function which is required to be called before any action can be ** performed. ** ******************************************************************************/ /*---------------------------------------------------------------------------*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif void init_bibtool _ARG((char * progname)); /* init.c */ BibTool/include/bibtool/key.h0000644000175100017510000000551012646460337015062 0ustar genegene/*** key.h ******************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file provides functions to deal with keys as they ** are defined in |keys.h|. ** ** This header file automaticall includes the header files ** |database.h| and |sbuffer.h| since datatypes defined there are ** required. ** ******************************************************************************/ #include #include #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String get_field _ARG((DB db, Record rec, String name));/* key.c */ String fmt_expand _ARG((StringBuffer *sb, String cp, DB db, Record rec));/* key.c*/ int apply_fmt _ARG((StringBuffer *sb,char *fmt,Record rec,DB db));/* key.c */ int foreach_ignored_word _ARG((int (*fct)_ARG((String))));/* key.c */ int mark_key _ARG((DB db,Record rec)); /* key.c */ int set_field _ARG((DB db,Record rec,String name,String value));/* key.c */ void add_format _ARG((char *s)); /* key.c */ void add_ignored_word _ARG((String s)); /* key.c */ void add_sort_format _ARG((char *s)); /* key.c */ void clear_ignored_words _ARG((void)); /* key.c */ void def_format_type _ARG((String s)); /* key.c */ void end_key_gen _ARG((void)); /* key.c */ void free_key_node _ARG((KeyNode kn)); /* key.c */ void make_key _ARG((DB db,Record rec)); /* key.c */ void make_sort_key _ARG((DB db,Record rec)); /* key.c */ void set_base _ARG((String value)); /* key.c */ void set_separator _ARG((int n,String s)); /* key.c */ void start_key_gen _ARG((void)); /* key.c */ BibTool/include/bibtool/keynode.h0000644000175100017510000000472212646460344015732 0ustar genegene/*** keynode.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file provides the datatype of a keynode. This is ** an internal structure which is used to built parse trees from ** format specifications. Usually this is done in |key.c| and ** should not be visible outside. ** ******************************************************************************/ #include /*----------------------------------------------------------------------------- ** Typedef: KeyNode ** Purpose: ** ** **___________________________________________________ */ typedef struct kEYnODE /* */ { short int kn_type; short int kn_pre; short int kn_post; String kn_string; String kn_from; String kn_to; struct kEYnODE *kn_next; struct kEYnODE *kn_then; struct kEYnODE *kn_else; } *KeyNode, SKeyNode; /* */ #define NodeType(X) ((X)->kn_type) #define NodePre(X) ((X)->kn_pre) #define NodePost(X) ((X)->kn_post) #define NodeSymbol(X) ((X)->kn_string) #define NodeNext(X) ((X)->kn_next) #define NodeThen(X) ((X)->kn_then) #define NodeElse(X) ((X)->kn_else) #ifdef REGEX #define NodeFrom(X) ((X)->kn_from) #define NodeTo(X) ((X)->kn_to) #endif #define NodeCountMask 0x100 #define NodePlusMask 0x200 #define NodeMinusMask 0x400 #define NodeSTRING 0x800 #define NodeTEST 0x801 #define NodeTESTneg 0x802 #define NodeOR 0x803 #define NodeSPECIAL 0x804 BibTool/include/bibtool/macros.h0000644000175100017510000001171112646460351015552 0ustar genegene/*** macros.h ***************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file contains definitions for the |Macro| ** structure. |Macro| is the pointer type corresponding to the ** structure |SMacro|. All C macros and functions provided ** through this header file deal with the pointer type. The ** structure itself is used in the allocation function only. ** ******************************************************************************/ #include /*----------------------------------------------------------------------------- ** Typedef: Macro ** Purpose: This is a pointer type to represent a mapping from a ** string to another string. This mapping is accompanied ** by a counter which can be used as a reference count. **___________________________________________________ */ typedef struct mACRO /* */ { String mc_name; /* Name of the macro. */ String mc_value; /* Value of the macro. */ int mc_used; /* Reference count. */ struct mACRO *mc_next; /* Pointer the next macro.*/ } SMacro, *Macro; /* */ /*----------------------------------------------------------------------------- ** Constant: MacroNULL() ** Type: Macro ** Purpose: This is the |NULL| pointer for the |Macro| type. It ** can be used as a special or illlegal macro. **___________________________________________________ */ #define MacroNULL (Macro)0 /*----------------------------------------------------------------------------- ** Macro: MacroName() ** Type: String ** Purpose: This is the functional representation of the name ** component of a |Macro|. It can be used to extract this ** information. It can also be used as a lvalue. ** Arguments: ** M |Macro| to consider **___________________________________________________ */ #define MacroName(M) ((M)->mc_name) /*----------------------------------------------------------------------------- ** Macro: MacroValue() ** Type: String ** Purpose: This is the functional representation of the value ** component of a |Macro|. It can be used to extract this ** information. It can also be used as a lvalue. ** Arguments: ** M |Macro| to consider **___________________________________________________ */ #define MacroValue(M) ((M)->mc_value) /*----------------------------------------------------------------------------- ** Macro: MacroCount() ** Type: int ** Purpose: This is the functional representation of the counter ** component of a |Macro|. It can be used to extract this ** information. It can also be used as a lvalue. ** Arguments: ** M |Macro| to consider **___________________________________________________ */ #define MacroCount(M) ((M)->mc_used) /*----------------------------------------------------------------------------- ** Macro: NextMacro() ** Type: Macro ** Purpose: This is the functional representation of the next ** |Macro|. It can be used to extract this information. ** It can also be used as a lvalue. ** Arguments: ** M |Macro| to consider **___________________________________________________ */ #define NextMacro(M) ((M)->mc_next) #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif Macro new_macro _ARG((String name,String val,Macro next,int count));/* macros.c*/ String get_item _ARG((String name,int type)); /* macros.c */ String get_key_name _ARG((String s)); /* macros.c */ String look_macro _ARG((String name,int add)); /* macros.c */ int def_macro _ARG((String name,String val,int count));/* macros.c */ void def_field_type _ARG((String s)); /* macros.c */ void dump_mac _ARG((char *fname,int allp)); /* macros.c */ void foreach_macro _ARG((int (*fct) _ARG((String , String))));/* macros.c */ void free_macro _ARG((Macro mac)); /* macros.c */ void init_macros _ARG((void)); /* macros.c */ void save_key _ARG((String s, String key)); /* macros.c */ BibTool/include/bibtool/names.h0000644000175100017510000001211412646460360015367 0ustar genegene/*** names.h ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include /*----------------------------------------------------------------------------- ** Typedef: SNameNode ** Purpose: The name format is translated internally into a list ** of nodes which are easier to evaluate since they avoid ** the reparsing of the format. This structure contains ** such a node. **___________________________________________________ */ typedef struct nameNODE /* */ { int nn_type; /* */ int nn_strip; /* */ int nn_trim; /* */ String nn_pre; /* */ String nn_mid; /* */ String nn_post; /* */ struct nameNODE *nn_next; /* Pointer to the next */ /* name node */ } SNameNode, *NameNode; /* */ /*----------------------------------------------------------------------------- ** Constant: NameNULL() ** Type: NameNode ** Purpose: The |NULL| pointer to a |NameNode| which can be used ** as a special value to indicate the end of a |NameNode| ** list. ** Returns: The |NULL| pointer to a |NameNode|. **___________________________________________________ */ #define NameNULL ((NameNode)0) /*----------------------------------------------------------------------------- ** Macro: NameType() ** Type: int ** Purpose: ** ** ** Arguments: ** NN ** Returns: **___________________________________________________ */ #define NameType(NN) ((NN)->nn_type) /*----------------------------------------------------------------------------- ** Macro: NameStrip() ** Type: int ** Purpose: ** ** ** Arguments: ** NN ** Returns: **___________________________________________________ */ #define NameStrip(NN) ((NN)->nn_strip) /*----------------------------------------------------------------------------- ** Macro: NameTrim() ** Type: int ** Purpose: ** ** ** Arguments: ** NN ** Returns: **___________________________________________________ */ #define NameTrim(NN) ((NN)->nn_trim) /*----------------------------------------------------------------------------- ** Macro: NamePre() ** Type: String ** Purpose: ** ** ** Arguments: ** NN ** Returns: **___________________________________________________ */ #define NamePre(NN) ((NN)->nn_pre) /*----------------------------------------------------------------------------- ** Macro: NameMid() ** Type: String ** Purpose: ** ** ** Arguments: ** NN ** Returns: **___________________________________________________ */ #define NameMid(NN) ((NN)->nn_mid) /*----------------------------------------------------------------------------- ** Macro: NamePost() ** Type: String ** Purpose: ** ** ** Arguments: ** NN ** Returns: **___________________________________________________ */ #define NamePost(NN) ((NN)->nn_post) /*----------------------------------------------------------------------------- ** Macro: NextName() ** Type: NameNode ** Purpose: Functional representation of the pointer to the next ** |NameNode|. ** Arguments: ** NN |NameNode| to consider. ** Returns: The next |Namenode|. **___________________________________________________ */ #define NextName(NN) ((NN)->nn_next) #define NoName 0x00 #define NameFirst 0x01 #define NameLast 0x02 #define NameVon 0x03 #define NameJr 0x04 #define NameString 0x05 #define NameNone 0x00 #define NameLower 0x10 #define NameUpper 0x20 #define NameExternal 0x30 #define NameTypeMask 0x0f #define NameTranslationMask 0xf0 #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif NameNode name_format _ARG((String s)); /* names.c */ String pp_list_of_names _ARG((String *wa,NameNode format,String trans,int max,String comma,String and,char *namesep,char *etal));/* names.c*/ char * pp_names _ARG((char *s,NameNode format,String trans,int max,char *namesep,char *etal));/* names.c*/ /*---------------------------------------------------------------------------*/ BibTool/include/bibtool/parse.h0000644000175100017510000000341012646460366015403 0ustar genegene/*** parse.h ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file contains functions which deal with the ** parsing of \BibTeX{} files. They are defined in |parse.c| and ** declared in this file. ** ******************************************************************************/ #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int parse_bib _ARG((Record rec)); /* parse.c */ int read_rsc _ARG((String name)); /* parse.c */ int see_bib _ARG((String fname)); /* parse.c */ int seen _ARG((void)); /* parse.c */ void init_read _ARG((void)); /* parse.c */ void set_rsc_path _ARG((String val)); /* parse.c */ BibTool/include/bibtool/print.h0000644000175100017510000000356012646460373015431 0ustar genegene/*** print.h ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file provides access to the functions and ** variables defined in |print.c|. Consult also the documentation ** of this file for details. ** ** This header file automatically includes |record.h| and |database.h|. ** ******************************************************************************/ #include #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif char *sput_record _ARG((Record rec,DB db,String start));/* print.c */ void fput_record _ARG((FILE *file,Record rec,DB db,String start));/* print.c*/ void put_record _ARG((int (*fct)_ARG((int)),Record rec,DB db, String start));/* print.c*/ void set_key_type _ARG((String s)); /* print.c */ void set_symbol_type _ARG((String s)); /* print.c */ BibTool/include/bibtool/pxfile.h0000644000175100017510000000314012646460400015545 0ustar genegene/*** pxfile.h ***************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module provides access to the functions and ** variables defined in |pxfile.c|. Consult also the documentation ** of this file for details. ** ** This header file automatically includes |bibtool.h| and ||. ** ******************************************************************************/ #include extern char * px_filename; extern FILE * px_fopen( #ifdef __STDC__ char * name, char * mode, char **pattern, char **path, int (*show)() #endif ); extern char **px_s2p( #ifdef __STDC__ char * s, int sep #endif ); BibTool/include/bibtool/regex.h0000644000175100017510000004441612646452011015402 0ustar genegene/* Definitions for data structures and routines for the regular expression library, version 0.12. Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __REGEXP_LIBRARY_H__ #define __REGEXP_LIBRARY_H__ /* POSIX says that must be included (by the caller) before . */ #ifdef VMS /* VMS doesn't have `size_t' in , even though POSIX says it should be there. */ #include #endif /* The following bits are used to determine the regexp syntax we recognize. The set/not-set meanings are chosen so that Emacs syntax remains the value 0. The bits are given in alphabetical order, and the definitions shifted by one from the previous bit; thus, when we add or remove a bit, only one other definition need change. */ typedef unsigned reg_syntax_t; /* If this bit is not set, then \ inside a bracket expression is literal. If set, then such a \ quotes the following character. */ #define RE_BACKSLASH_ESCAPE_IN_LISTS (1) /* If this bit is not set, then + and ? are operators, and \+ and \? are literals. If set, then \+ and \? are operators and + and ? are literals. */ #define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) /* If this bit is set, then character classes are supported. They are: [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. If not set, then character classes are not supported. */ #define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) /* If this bit is set, then ^ and $ are always anchors (outside bracket expressions, of course). If this bit is not set, then it depends: ^ is an anchor if it is at the beginning of a regular expression or after an open-group or an alternation operator; $ is an anchor if it is at the end of a regular expression, or before a close-group or an alternation operator. This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because POSIX draft 11.2 says that * etc. in leading positions is undefined. We already implemented a previous draft which made those constructs invalid, though, so we haven't changed the code back. */ #define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) /* If this bit is set, then special characters are always special regardless of where they are in the pattern. If this bit is not set, then special characters are special only in some contexts; otherwise they are ordinary. Specifically, * + ? and intervals are only special when not after the beginning, open-group, or alternation operator. */ #define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) /* If this bit is set, then *, +, ?, and { cannot be first in an re or immediately after an alternation or begin-group operator. */ #define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) /* If this bit is set, then . matches newline. If not set, then it doesn't. */ #define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) /* If this bit is set, then . doesn't match NUL. If not set, then it does. */ #define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) /* If this bit is set, nonmatching lists [^...] do not match newline. If not set, they do. */ #define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) /* If this bit is set, either \{...\} or {...} defines an interval, depending on RE_NO_BK_BRACES. If not set, \{, \}, {, and } are literals. */ #define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) /* If this bit is set, +, ? and | aren't recognized as operators. If not set, they are. */ #define RE_LIMITED_OPS (RE_INTERVALS << 1) /* If this bit is set, newline is an alternation operator. If not set, newline is literal. */ #define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) /* If this bit is set, then `{...}' defines an interval, and \{ and \} are literals. If not set, then `\{...\}' defines an interval. */ #define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) /* If this bit is set, (...) defines a group, and \( and \) are literals. If not set, \(...\) defines a group, and ( and ) are literals. */ #define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) /* If this bit is set, then \ matches . If not set, then \ is a back-reference. */ #define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) /* If this bit is set, then | is an alternation operator, and \| is literal. If not set, then \| is an alternation operator, and | is literal. */ #define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) /* If this bit is set, then an ending range point collating higher than the starting range point, as in [z-a], is invalid. If not set, then when ending range point collates higher than the starting range point, the range is ignored. */ #define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) /* If this bit is set, then an unmatched ) is ordinary. If not set, then an unmatched ) is invalid. */ #define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) /* This global variable defines the particular regexp syntax to use (for some interfaces). When a regexp is compiled, the syntax used is stored in the pattern buffer, so changing this does not affect already-compiled regexps. */ extern reg_syntax_t re_syntax_options; /* Define combinations of the above bits for the standard possibilities. (The [[[ comments delimit what gets put into the Texinfo file, so don't delete them!) */ /* [[[begin syntaxes]]] */ #define RE_SYNTAX_EMACS 0 #define RE_SYNTAX_AWK \ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ | RE_UNMATCHED_RIGHT_PAREN_ORD) #define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) #define RE_SYNTAX_GREP \ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ | RE_NEWLINE_ALT) #define RE_SYNTAX_EGREP \ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ | RE_NO_BK_VBAR) #define RE_SYNTAX_POSIX_EGREP \ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ #define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC #define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC /* Syntax bits common to both basic and extended POSIX regex syntax. */ #define _RE_SYNTAX_POSIX_COMMON \ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ | RE_INTERVALS | RE_NO_EMPTY_RANGES) #define RE_SYNTAX_POSIX_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this isn't minimal, since other operators, such as \`, aren't disabled. */ #define RE_SYNTAX_POSIX_MINIMAL_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) #define RE_SYNTAX_POSIX_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ | RE_UNMATCHED_RIGHT_PAREN_ORD) /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ #define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) /* [[[end syntaxes]]] */ /* Maximum number of duplicates an interval can allow. Some systems (erroneously) define this in other header files, but we want our value, so remove any previous define. */ #ifdef RE_DUP_MAX #undef RE_DUP_MAX #endif #define RE_DUP_MAX ((1 << 15) - 1) /* POSIX `cflags' bits (i.e., information for `regcomp'). */ /* If this bit is set, then use extended regular expression syntax. If not set, then use basic regular expression syntax. */ #define REG_EXTENDED 1 /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ #define REG_ICASE (REG_EXTENDED << 1) /* If this bit is set, then anchors do not match at newline characters in the string. If not set, then anchors do match at newlines. */ #define REG_NEWLINE (REG_ICASE << 1) /* If this bit is set, then report only success or fail in regexec. If not set, then returns differ between not matching and errors. */ #define REG_NOSUB (REG_NEWLINE << 1) /* POSIX `eflags' bits (i.e., information for regexec). */ /* If this bit is set, then the beginning-of-line operator doesn't match the beginning of the string (presumably because it's not the beginning of a line). If not set, then the beginning-of-line operator does match the beginning of the string. */ #define REG_NOTBOL 1 /* Like REG_NOTBOL, except for the end-of-line. */ #define REG_NOTEOL (1 << 1) /* If any error codes are removed, changed, or added, update the `re_error_msg' table in regex.c. */ typedef enum { REG_NOERROR = 0, /* Success. */ REG_NOMATCH, /* Didn't find a match (for regexec). */ /* POSIX regcomp return error codes. (In the order listed in the standard.) */ REG_BADPAT, /* Invalid pattern. */ REG_ECOLLATE, /* Not implemented. */ REG_ECTYPE, /* Invalid character class name. */ REG_EESCAPE, /* Trailing backslash. */ REG_ESUBREG, /* Invalid back reference. */ REG_EBRACK, /* Unmatched left bracket. */ REG_EPAREN, /* Parenthesis imbalance. */ REG_EBRACE, /* Unmatched \{. */ REG_BADBR, /* Invalid contents of \{\}. */ REG_ERANGE, /* Invalid range end. */ REG_ESPACE, /* Ran out of memory. */ REG_BADRPT, /* No preceding re for repetition op. */ /* Error codes we've added. */ REG_EEND, /* Premature end. */ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ } reg_errcode_t; /* This data structure represents a compiled pattern. Before calling the pattern compiler, the fields `buffer', `allocated', `fastmap', `translate', and `no_sub' can be set. After the pattern has been compiled, the `re_nsub' field is available. All other fields are private to the regex routines. */ struct re_pattern_buffer { /* [[[begin pattern_buffer]]] */ /* Space that holds the compiled pattern. It is declared as `unsigned char *' because its elements are sometimes used as array indexes. */ unsigned char *buffer; /* Number of bytes to which `buffer' points. */ unsigned long allocated; /* Number of bytes actually used in `buffer'. */ unsigned long used; /* Syntax setting with which the pattern was compiled. */ reg_syntax_t syntax; /* Pointer to a fastmap, if any, otherwise zero. re_search uses the fastmap, if there is one, to skip over impossible starting points for matches. */ char *fastmap; /* Either a translate table to apply to all characters before comparing them, or zero for no translation. The translation is applied to a pattern when it is compiled and to a string when it is matched. */ char *translate; /* Number of subexpressions found by the compiler. */ size_t re_nsub; /* Zero if this pattern cannot match the empty string, one else. Well, in truth it's used only in `re_search_2', to see whether or not we should use the fastmap, so we don't set this absolutely perfectly; see `re_compile_fastmap' (the `duplicate' case). */ unsigned can_be_null : 1; /* If REGS_UNALLOCATED, allocate space in the `regs' structure for `max (RE_NREGS, re_nsub + 1)' groups. If REGS_REALLOCATE, reallocate space if necessary. If REGS_FIXED, use what's there. */ #define REGS_UNALLOCATED 0 #define REGS_REALLOCATE 1 #define REGS_FIXED 2 unsigned regs_allocated : 2; /* Set to zero when `regex_compile' compiles a pattern; set to one by `re_compile_fastmap' if it updates the fastmap. */ unsigned fastmap_accurate : 1; /* If set, `re_match_2' does not return information about subexpressions. */ unsigned no_sub : 1; /* If set, a beginning-of-line anchor doesn't match at the beginning of the string. */ unsigned not_bol : 1; /* Similarly for an end-of-line anchor. */ unsigned not_eol : 1; /* If true, an anchor at a newline matches. */ unsigned newline_anchor : 1; /* [[[end pattern_buffer]]] */ }; typedef struct re_pattern_buffer regex_t; /* search.c (search_buffer) in Emacs needs this one opcode value. It is defined both in `regex.c' and here. */ #define RE_EXACTN_VALUE 1 /* Type for byte offsets within the string. POSIX mandates this. */ typedef int regoff_t; /* This is the structure we store register match data in. See regex.texinfo for a full description of what registers match. */ struct re_registers { unsigned num_regs; regoff_t *start; regoff_t *end; }; /* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, `re_match_2' returns information about at least this many registers the first time a `regs' structure is passed. */ #ifndef RE_NREGS #define RE_NREGS 30 #endif /* POSIX specification for registers. Aside from the different names than `re_registers', POSIX uses an array of structures, instead of a structure of arrays. */ typedef struct { regoff_t rm_so; /* Byte offset from string's start to substring's start. */ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ } regmatch_t; /* Declarations for routines. */ /* To avoid duplicating every routine declaration -- once with a prototype (if we are ANSI), and once without (if we aren't) -- we use the following macro to declare argument types. This unfortunately clutters up the declarations a bit, but I think it's worth it. */ #if __STDC__ #define _RE_ARGS(args) args #else /* not __STDC__ */ #define _RE_ARGS(args) () #endif /* not __STDC__ */ /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); /* Compile the regular expression PATTERN, with length LENGTH and syntax given by the global `re_syntax_options', into the buffer BUFFER. Return NULL if successful, and an error string if not. */ extern const char *re_compile_pattern _RE_ARGS ((const char *pattern, int length, struct re_pattern_buffer *buffer)); /* Compile a fastmap for the compiled pattern in BUFFER; used to accelerate searches. Return 0 if successful and -2 if was an internal error. */ extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); /* Search in the string STRING (with length LENGTH) for the pattern compiled into BUFFER. Start searching at position START, for RANGE characters. Return the starting position of the match, -1 for no match, or -2 for an internal error. Also return register information in REGS (if REGS and BUFFER->no_sub are nonzero). */ extern int re_search _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, int length, int start, int range, struct re_registers *regs)); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ extern int re_search_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, int stop)); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ extern int re_match _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, int length, int start, struct re_registers *regs)); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ extern int re_match_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, int length1, const char *string2, int length2, int start, struct re_registers *regs, int stop)); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using BUFFER and REGS will use this memory for recording register information. STARTS and ENDS must be allocated with malloc, and must each be at least `NUM_REGS * sizeof (regoff_t)' bytes long. If NUM_REGS == 0, then subsequent matches should allocate their own register data. Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ extern void re_set_registers _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, unsigned num_regs, regoff_t *starts, regoff_t *ends)); /* 4.2 bsd compatibility. */ extern char *re_comp _RE_ARGS ((const char *)); extern int re_exec _RE_ARGS ((const char *)); /* POSIX compatibility. */ extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); extern int regexec _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)); extern size_t regerror _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)); extern void regfree _RE_ARGS ((regex_t *preg)); #endif /* not __REGEXP_LIBRARY_H__ */ /* Local variables: make-backup-files: t version-control: t trim-versions-without-asking: nil End: */ BibTool/include/bibtool/record.h0000644000175100017510000003570112646460404015550 0ustar genegene/*** record.h ***************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module contains functions which deal with records in databases. ** ** ******************************************************************************/ #ifndef RecordNULL #include #include /*----------------------------------------------------------------------------- ** Typedef: Record ** Purpose: This data type represents a record in a \BibTeX{} ** database. Since the record can contain an arbitrary ** number of fields the central r\^ole is taken by the ** dynamic array |rc_heap|. This array contains at even ** positions the name of the field and the following odd ** position the associated value. In normal records the ** position 0 contains the reference key of the record. ** ** If a field is deleted then the name is replaced by a ** |NULL|. The structure member |rc_free| contains the ** size of the heap. ** ** The type of the record is determined by the integer ** |rc_type|. ** **________________________________________________ */ typedef struct rECORD /* */ { String rc_key; /* The sort key. */ String rc_old_key; /* The old sort key. */ int rc_type; /* The type of the record. */ int rc_flags; /* Some bits; e.g. used */ /* during selecting aux */ /* records. */ int rc_free; /* The size of the heap. This*/ /* is purely internal and */ /* must not be modified. */ String *rc_heap; /* The heap. */ String rc_comment; /* The comment following */ /* the given record. */ String rc_source; /* The source of the record. */ /* I.e. the file name it */ /* has been read from. */ struct rECORD *rc_next; /* Pointer to the next */ /* record. */ struct rECORD *rc_prev; /* Pointer to the previous */ /* record. */ } SRecord, *Record; /* */ /*----------------------------------------------------------------------------- ** Constant: RecordNULL ** Type: Record ** Purpose: Symbolic constant for the NULL pointer of type ** |Record|. This is used as special (invalid) record. **___________________________________________________ */ #define RecordNULL (Record)0 /*----------------------------------------------------------------------------- ** Macro: RecordType() ** Type: int ** Purpose: Functional representation of the record ** token. This can be used to access the token component ** of a record. It can also be used as lvalue. ** ** Arguments: ** R Record to consider. ** Returns: The pure token. **___________________________________________________ */ #define RecordType(R) ((R)->rc_type) /*----------------------------------------------------------------------------- ** Macro: RecordFlags() ** Type: int ** Purpose: Functional representation of the record type. This ** can be used to access the token component of a ** record. It can also be used as lvalue. ** Arguments: ** R Record to consider. ** Returns: The flags as integer. **___________________________________________________ */ #define RecordFlags(R) ((R)->rc_flags) #define RecordIs(R,F) (RecordFlags(R)&(F)) #define RecordHas(R,F) (RecordFlags(R)&(F)) #define RecordSet(R,F) (RecordFlags(R) |= (F)) #define RecordClear(R,F) (RecordFlags(R) &= ~(F)) /*----------------------------------------------------------------------------- ** Constant: RecordFlagMARKED ** Type: int ** Purpose: Bit mask for the |MARKED| flag of a record. The mark ** is used temporarily to determine certain records; ** e.g. during gc. ** ** This macro is usually not used directly but implicitly ** with other macros from this header file. **___________________________________________________ */ #define RecordFlagMARKED 0x01 /*----------------------------------------------------------------------------- ** Constant: RecordFlagXREF ** Type: int ** Purpose: Bit mask for the |XREF| flag of a record. This flag is ** maintained to indicate that the record contains an ** |crossref| field. This is done for efficiency reasons ** only. ** ** This macro is usually not used directly but implicitly ** with other macros from this header file. **___________________________________________________ */ #define RecordFlagXREF 0x02 /*----------------------------------------------------------------------------- ** Constant: RecordFlagDELETED ** Type: int ** Purpose: Bit mask for the |DELETED| flag of a record. This ** flag indicates that the record has been deleted. To ** avoid dangling pointers the deleted records are not ** removed from the database immediately but a call to ** |record_gc()| performs this cleanup. In the meantime ** the deleted records are just left in the chain. Many ** operations automatically ignore deleted records. ** ** This macro is usually not used directly but implicitly ** with other macros from this header file. **___________________________________________________ */ #define RecordFlagDELETED 0x04 /*----------------------------------------------------------------------------- ** Macro: SetRecordXREF() ** Type: int ** Purpose: Mark the record with the |XREF| flag. If it is marked ** already nothing is done. ** ** The |XREF| flag is used to mark those records which ** contain a |crossref| field. This is done for ** efficiency only. ** Arguments: ** R The record to consider. ** Returns: The new value of the record flags. **___________________________________________________ */ #define SetRecordXREF(R) (RecordFlags(R) |= RecordFlagXREF) /*----------------------------------------------------------------------------- ** Macro: ClearRecordXREF() ** Type: int ** Purpose: Remove the XREF mark. ** Arguments: ** R The record to consider. ** Returns: The new value of the record flags. **___________________________________________________ */ #define ClearRecordXREF(R) (RecordFlags(R) &= ~RecordFlagXREF) /*----------------------------------------------------------------------------- ** Macro: RecordIsXREF() ** Type: int ** Purpose: Check whether the |XREF| flag of a record is set. ** Arguments: ** R Record to consider. ** Returns: |FALSE| iff the |XREF| flag is not set. **___________________________________________________ */ #define RecordIsXREF(R) (RecordFlags(R) & RecordFlagXREF) /*----------------------------------------------------------------------------- ** Macro: SetRecordDELETED() ** Type: int ** Purpose: Mark the record with the |DELETED| flag. If it is marked ** already nothing is done. ** ** The |DELETED| flag is used to mark those records which ** should be treated as non existent. Deleted records are ** ignored for most operations. ** Arguments: ** R Record to consider. ** Returns: The new value of the record flags. **___________________________________________________ */ #define SetRecordDELETED(R) (RecordFlags(R) |= RecordFlagDELETED) /*----------------------------------------------------------------------------- ** Macro: ClearRecordDELETED() ** Type: int ** Purpose: Remove the deleted flag. Thus you can effictively ** undelete a record as long as its memory has not been ** released. ** Arguments: ** R Record to consider. ** Returns: The new value of the record flags. **___________________________________________________ */ #define ClearRecordDELETED(R) (RecordFlags(R) &= ~RecordFlagDELETED) /*----------------------------------------------------------------------------- ** Macro: RecordIsDELETED() ** Type: int ** Purpose: Check whether the record is marked as deleted. ** Arguments: ** R Record to consider. ** Returns: |FALSE| iff the |DELETED| flag is not set. **___________________________________________________ */ #define RecordIsDELETED(R) (RecordFlags(R) & RecordFlagDELETED) /*----------------------------------------------------------------------------- ** Macro: SetRecordMARK() ** Type: int ** Purpose: Mark the record. The mark is used temporarily. Do not ** assume that the mark is preserved in each function. ** Arguments: ** R Record to consider. ** Returns: The new value of the record flags. **___________________________________________________ */ #define SetRecordMARK(R) (RecordFlags(R) |= RecordFlagMARKED) /*----------------------------------------------------------------------------- ** Macro: ClearRecordMARK() ** Type: int ** Purpose: Remove the deleted flag. Thus you can effictively ** undelete a record as long as its memory has not been ** released. ** Arguments: ** R Record to consider. ** Returns: The new value of the record flags. **___________________________________________________ */ #define ClearRecordMARK(R) (RecordFlags(R) &= ~RecordFlagMARKED) /*----------------------------------------------------------------------------- ** Macro: RecordIsMARKED() ** Type: int ** Purpose: Check whether the record is marked as deleted. ** Arguments: ** R Record to consider. ** Returns: |FALSE| iff the |DELETED| flag is not set. **___________________________________________________ */ #define RecordIsMARKED(R) (RecordFlags(R) & RecordFlagMARKED) /*----------------------------------------------------------------------------- ** Macro: RecordOldKey() ** Type: String ** Purpose: ** ** ** Arguments: ** R Record to consider **___________________________________________________ */ #define RecordOldKey(R) ((R)->rc_old_key) /*----------------------------------------------------------------------------- ** Macro: RecordSortkey() ** Type: String ** Purpose: This is the functional representation of the sort key ** of a record. This can be used to access the key component ** of a record. It can also be used as lvalue. ** ** Note that the reference key of a normal record is ** stored in the heap at position 0. ** Arguments: ** R Record to consider. **___________________________________________________ */ #define RecordSortkey(R) ((R)->rc_key) /*----------------------------------------------------------------------------- ** Macro*: RecordFree() ** Type: int ** Purpose: This is the functional representation of the first ** free position on the heap. ** Arguments: ** R Record to consider **___________________________________________________ */ #define RecordFree(R) ((R)->rc_free) /*----------------------------------------------------------------------------- ** Macro: RecordHeap() ** Type: String * ** Purpose: The heap of a record is a array of strings. The even ** positions contain the names of fields and the ** following array cell contains its value. If the name ** or value is |NULL| then this slot is not used. Thus it ** is easy to delete a field. Simply write a |NULL| into ** the appropriate place. ** Arguments: ** R Record to consider. **___________________________________________________ */ #define RecordHeap(R) ((R)->rc_heap) /*----------------------------------------------------------------------------- ** Macro: NextRecord() ** Type: Record ** Purpose: This is the functional representation of the next ** record of a record. It can be used to get this value ** as well as an lvalue to set it. ** Arguments: ** R Record to consider **___________________________________________________ */ #define NextRecord(R) ((R)->rc_next) /*----------------------------------------------------------------------------- ** Macro: PrevRecord() ** Type: Record ** Purpose: This is the functional representation of the previous ** record of a record. It can be used to get this value ** as well as an lvalue to set it. ** Arguments: ** R Record to consider **___________________________________________________ */ #define PrevRecord(R) ((R)->rc_prev) /*----------------------------------------------------------------------------- ** Macro: RecordComment() ** Type: String ** Purpose: This is the functional representation of the comment ** component of a record. It can be used to get this value ** as well as an lvalue to set it. ** Arguments: ** R Record to consider **___________________________________________________ */ #define RecordComment(R) ((R)->rc_comment) /*----------------------------------------------------------------------------- ** Macro: RecordSource() ** Type: String ** Purpose: This is the functional representation of the source ** indicator of a record. It is a string containing the ** file name from which this record has been read. The ** empty string is used to denote unknown sources. ** Arguments: ** R Record to consider ** Returns: **___________________________________________________ */ #define RecordSource(R) ((R)->rc_source) /*----------------------------------------------------------------------------- ** Macro: RecordFlags() ** Type: int ** Purpose: This is the functional representation of the record ** flags. They are extra bits used for arbitrary ** purposes. Right now only the bit with the mask 1 is ** used for selecting the records found in an aux file. ** Arguments: ** R Record to consider ** Returns: **___________________________________________________ */ #define RecordFlags(R) ((R)->rc_flags) #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif Record copy_record _ARG((Record rec)); /* record.c */ Record new_record _ARG((int token,int size)); /* record.c */ Record record_gc _ARG((Record rec)); /* record.c */ Record unlink_record _ARG((Record rec)); /* record.c */ WordList new_wordlist _ARG((String s)); /* record.c */ void add_sort_order _ARG((String val)); /* record.c */ void free_1_record _ARG((Record rec)); /* record.c */ void free_record _ARG((Record rec)); /* record.c */ void provide_to_record _ARG((Record rec,String s, String t));/* */ void push_to_record _ARG((Record rec,String s, String t));/* record.c */ void sort_record _ARG((Record rec)); /* record.c */ #endif BibTool/include/bibtool/resource.h0000644000175100017510000002277512646460420016126 0ustar genegene/*** resource.h *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This file is the central component of the resource evaluator. ** To reduce redundancy everything in this file is encapsulated ** with macros. Thus it is possible to adapt the meaning ** according to the task to be performed. ** ** This file is included several times from different places. One ** task is the definition of certain variables used in this ** file. Another task is the execution of the commands associated ** with a command name. ** ** This is one place where the power and the beauty of the C ** preprocessor makes live easy. It should also be fun to figure out ** the three ways in which this file is used. Read the sources and ** enjoy it! ** ** For the normal user this file is consulted automatically when ** the header file |rsc.h| is used. ** ******************************************************************************/ #ifndef RSC_FIRST #define RSC_FIRST(C) #endif #ifndef RSC_NEXT #define RSC_NEXT(C) #endif #ifndef RscTerm #define RscTerm(NAME,VALUE) #endif RSC_FIRST('a') RscByFct( "add.field" , r_af ,add_field(val) ) RscBoolean( "apply.alias" , r_aa ,rsc_apply_alias , FALSE ) RscBoolean( "apply.modify" , r_am ,rsc_apply_modify , FALSE ) RscBoolean( "apply.include" , r_ai ,rsc_apply_include , FALSE ) RscTerm( "and" , RSC_INIT_AND ) RSC_NEXT('b') RscString( "bibtex.env.name" , r_ben ,rsc_e_bibtex , RSC_BIBINPUTS ) RscString( "bibtex.search.path" , r_bsp ,rsc_v_bibtex ,RSC_BIBINPUTS_DEFAULT ) RSC_NEXT('c') RscBoolean( "check.double" , r_cd ,rsc_double_check , FALSE ) RscBoolean( "check.double.delete" , r_cdd ,rsc_del_dbl , FALSE ) RscByFct( "check.rule" , r_cr ,add_check_rule(val) ) RscBoolean( "check.case.sensitive" , r_ccs ,rsc_case_check , TRUE ) RscByFct( "clear.ignored.words" , r_ciw ,clear_ignored_words() ) RscBoolean( "count.all" , r_ca ,rsc_cnt_all , FALSE ) RscBoolean( "count.used" , r_cu ,rsc_cnt_used , FALSE ) RscNumeric( "crossref.limit" , r_cl ,rsc_xref_limit , 32 ) RSC_NEXT('d') RscByFct( "default.key" , r_dk ,set_separator(0,val) ) RscByFct( "delete.field" , r_df ,add_rewrite_rule(val) ) RscString( "dir.file.separator" , r_dfs ,rsc_dir_file_sep , DIR_SEP ) RscBoolean( "dump.symbols" , r_ds ,rsc_dump_symbols , FALSE ) RSC_NEXT('e') RscString( "env.separator" , r_es ,rsc_env_sep , ENV_SEP ) RscByFct( "extract.file" , r_ef ,read_aux(val,save_input_file,FALSE)) RscByFct( "extract.regex" , r_er ,save_regex(val) ) RscBoolean( "expand.macros" , r_em ,rsc_expand_macros , FALSE ) RscBoolean( "expand.crossref" , r_ex ,rsc_expand_crossref, FALSE ) RSC_NEXT('f') RscByFct( "fmt.inter.name" , r_fin ,set_separator(1,val) ) RscByFct( "fmt.name.pre" , r_fnp ,set_separator(2,val) ) RscByFct( "fmt.name.name" , r_fnn ,set_separator(3,val) ) RscByFct( "fmt.name.title" , r_fnt ,set_separator(4,val) ) RscByFct( "fmt.title.title" , r_ftt ,set_separator(5,val) ) RscByFct( "fmt.et.al" , r_fea ,set_separator(7,val) ) RscByFct( "fmt.word.separator" , r_fws ,add_word_sep(val) ) RscByFct( "field.type" , r_ft ,set_symbol_type(val) ) RscTerm( "false" , RSC_INIT_FALSE ) RSC_NEXT('i') RscByFct( "input" , r_i ,save_input_file((char*)val) ) RscByFct( "ignored.word" , r_iw ,add_ignored_word(val) ) RscTerm( "ilike" , RSC_INIT_ILIKE ) RSC_NEXT('k') RscBoolean( "key.generation" , r_kg ,rsc_make_key , FALSE ) RscByFct( "key.base" , r_kb ,set_base(val) ) RscByFct( "key.format" , r_kf ,add_format((char*)val) ) RscBoolean( "key.make.alias" , r_ma ,rsc_make_alias , FALSE ) RscByFct( "key.number.separator" , r_kns ,set_separator(6,val) ) RscBoolean( "key.expand.macros" , r_kem ,rsc_key_expand_macros,TRUE ) RSC_NEXT('l') RscTerm( "like" , RSC_INIT_LIKE ) RSC_NEXT('m') RscByFct( "macro.file" , r_mf ,save_macro_file((char*)val) ) RscTerm( "mod" , RSC_INIT_MOD ) RSC_NEXT('n') RscByFct( "new.entry.type" , r_net ,def_entry_type(val) ) RscByFct( "new.field.type" , r_nft ,def_field_type(val) ) RscByFct( "new.format.type" , r_nfmt,def_format_type(val) ) RscTerm( "not" , RSC_INIT_NOT ) RscTerm( "nil" , RSC_INIT_NIL ) RSC_NEXT('o') RscByFct( "output.file" , r_of ,save_output_file((char*)val) ) RscTerm( "or" , RSC_INIT_OR ) RSC_NEXT('p') RscBoolean( "pass.comments" , r_pc ,rsc_pass_comment , FALSE ) RscBoolean( "preserve.key.case" , r_pkc ,rsc_key_case , FALSE ) RscBoolean( "preserve.keys" , r_pk ,rsc_key_preserve , FALSE ) RscByFct( "print" , r_p ,rsc_print(val) ) RscNumeric( "print.align.string" , r_pas ,rsc_col_s , 18 ) RscNumeric( "print.align.comment" , r_pac ,rsc_col_c , 10 ) RscNumeric( "print.align.preamble" , r_pap ,rsc_col_p , 11 ) RscNumeric( "print.align.key" , r_pak ,rsc_col_key , 18 ) RscNumeric( "print.align" , r_pa ,rsc_col , 18 ) RscBoolean( "print.all.strings" , r_pam ,rsc_all_macs , TRUE ) RscString( "print.entry.types" , r_pet ,rsc_print_et , "pisnmac") RscBoolean( "print.equal.right" , r_per ,rsc_eq_right , TRUE ) RscBoolean( "print.braces" , r_pb ,rsc_braces , TRUE ) RscBoolean( "print.comma.at.end" , r_pce ,rsc_print_ce , TRUE ) RscString( "print.deleted.prefix" , r_pdp ,rsc_del_pre , "###" ) RscBoolean( "print.deleted.entries" , r_pdr ,rsc_del_q , TRUE ) RscNumeric( "print.indent" , r_pi ,rsc_indent , 2 ) RscNumeric( "print.line.length" , r_pll ,rsc_linelen , 77 ) RscNumeric( "print.newline" , r_pnl ,rsc_newlines , 1 ) RscBoolean( "print.parentheses" , r_pp ,rsc_parentheses , FALSE ) RscBoolean( "print.terminal.comma" , r_ptc ,rsc_print_tc , FALSE ) RscBoolean( "print.use.tab" , r_put ,rsc_use_tabs , TRUE ) RscBoolean( "print.wide.equal" , r_pwe ,rsc_print_we , FALSE ) RSC_NEXT('q') RscBoolean( "quiet" , r_q ,rsc_quiet , FALSE ) RSC_NEXT('r') RscByFct( "regexp.syntax" , r_rs ,set_regex_syntax((char*)val) ) RscByFct( "rename.field" , r_rf ,rename_field(val) ) RscByFct( "resource" , r_r ,resource(val) ) RscByFct( "resource.search.path" , r_rsp ,set_rsc_path(val) ) RscByFct( "rewrite.rule" , r_rr ,add_rewrite_rule(val) ) RscBoolean( "rewrite.case.sensitive", r_rcs ,rsc_case_rewrite , TRUE ) RscNumeric( "rewrite.limit" , r_rl ,rsc_rewrite_limit , 512 ) RSC_NEXT('s') RscByFct( "select" , r_sel ,add_extract(val,TRUE,FALSE) ) RscByFct( "select.by.string" , r_sbs ,add_extract(val,FALSE,FALSE) ) RscByFct( "select.by.non.string" , r_sbns,add_extract(val,FALSE,TRUE) ) RscString( "select.by.string.ignored",r_seli,rsc_sel_ignored ,"{}\\[] ") RscBoolean( "select.case.sensitive" , r_scs ,rsc_case_select , FALSE ) RscString( "select.fields" , r_self,rsc_sel_fields , "$key" ) RscByFct( "select.non" , r_seln,add_extract(val,TRUE,TRUE) ) RscBoolean( "select.crossrefs" , r_sxc ,rsc_xref_select , FALSE ) RscBoolean( "sort" , r_s ,rsc_sort , FALSE ) RscBoolean( "sort.cased" , r_sc ,rsc_sort_cased , FALSE ) RscBoolean( "sort.macros" , r_sm ,rsc_srt_macs , TRUE ) RscBoolean( "sort.reverse" , r_sr ,rsc_sort_reverse , FALSE ) RscByFct( "sort.order" , r_so ,add_sort_order(val) ) RscByFct( "sort.format" , r_sf ,add_sort_format((char*)val) ) RscBoolean( "suppress.initial.newline", r_sin ,rsc_no_nl , FALSE ) RscByFct( "symbol.type" , r_st ,set_symbol_type(val) ) RSC_NEXT('t') RscByFct( "tex.define" , r_td ,TeX_def(val) ) RscTerm( "true" , RSC_INIT_TRUE ) RSC_NEXT('v') RscBoolean( "verbose" , r_v ,rsc_verbose , FALSE ) RscByFct( "version" , r_ver ,show_version() ) #undef RSC_FIRST #undef RSC_NEXT #undef RscNumeric #undef RscString #undef RscBoolean #undef RscByFct BibTool/include/bibtool/rewrite.h0000644000175100017510000000316412646460426015755 0ustar genegene/*** rewrite.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int is_selected _ARG((DB db, Record rec)); int set_regex_syntax _ARG((char* name)); void add_check_rule _ARG((String s)); void add_extract _ARG((String s, int regexp, int notp)); void add_field _ARG((String spec)); void add_rewrite_rule _ARG((String s)); void clear_addlist _ARG((void)); void remove_field _ARG((String field, Record rec)); void rename_field _ARG((String spec)); void rewrite_record _ARG((DB db, Record rec)); void save_regex _ARG((String s)); BibTool/include/bibtool/rsc.h0000644000175100017510000000451412646460432015060 0ustar genegene/*** rsc.h ******************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file provides definitions for all resource ** variables, i.e.\ the variables defined in the header file ** |resource.h|. ** ** In addition the functions defined in |resource.c| are made ** accessible to those modules including this header file. ******************************************************************************/ #include #ifdef RSC_INIT #define RscNumeric(SYM,S,V,I) int V = I; #define RscString(SYM,S,V,I) String V = (String)I; #define RscBoolean(SYM,S,V,I) int V = I; #define RscByFct(SYM,S,FCT) #define DECLARE(TYPE,VAR,VAL) TYPE VAR = VAL #else #define RscNumeric(SYM,S,V,I) extern int V; #define RscString(SYM,S,V,I) extern String V; #define RscBoolean(SYM,S,V,I) extern int V; #define RscByFct(SYM,S,FCT) #define DECLARE(TYPE,VAR,VAL) extern TYPE VAR #endif #include DECLARE( int , rsc_select , FALSE ); DECLARE( char* , rsc_e_rsc , RSC_BIBTOOL ); DECLARE( String , rsc_v_rsc , (String)(RSC_BIBTOOL_DEFAULT) ); #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int load_rsc _ARG((String name)); int resource _ARG((String name)); int search_rsc _ARG((void)); int set_rsc _ARG((String name,String val)); int use_rsc _ARG((String s)); void rsc_print _ARG((String s)); BibTool/include/bibtool/s_parse.h0000644000175100017510000000466712646460531015736 0ustar genegene/*** s_parse.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** ******************************************************************************/ #define StringParseSkip 256 #define StringParseNext 257 #define StringParseNumber 258 #define StringParseSymbol 259 #define StringParseString 260 #define StringParseUnquotedString 261 #define StringParseBraces 262 #define StringParseUnquotedBraces 263 #define StringParseEOS 264 #define StringParseValue 265 #define SParseSymbol(SP) s_parse(StringParseSymbol ,SP,-1) #define SParseOptionalSymbol(SP) s_parse(StringParseSymbol ,SP, 0) #define SParseString(SP) s_parse(StringParseString ,SP,-1) #define SParseUnquotedString(SP) s_parse(StringParseUnquotedString,SP,-1) #define SParseEOS(SP) s_parse(StringParseEOS ,SP,-1) #define SParseSkip(SP) s_parse(StringParseSkip ,SP,-1) #define SParseNext(SP) s_parse(StringParseNext ,SP,-1) #define SParseValue(SP) s_parse(StringParseValue ,SP,-1) #define SParseExpect(C,SP) s_parse(C&0xff ,SP,-1) #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String s_parse _ARG((int type, String *sp, int errp));/* s_parse.c */ int sp_open _ARG((String s)); /* s_parse.c */ void sp_close _ARG((void)); /* s_parse.c */ int sp_expect _ARG((String*sp, String expect)); /* s_parse.c */ BibTool/include/bibtool/sbuffer.h0000644000175100017510000000526512646460507015734 0ustar genegene/*** sbuffer.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file makes accessible the functions to treat ** strings like streams In addition to the functions defined in ** |sbuffer.c| one macro is defined here. ** ******************************************************************************/ #ifndef sbputchar typedef struct { char *sb__string; int sb__size; int sb__ptr; } StringBuffer; #define StringBufferIncrement 256 extern StringBuffer* sbopen( #ifdef __STDC__ void #endif ); extern int sbclose( #ifdef __STDC__ StringBuffer* #endif ); extern int sbputs( #ifdef __STDC__ char *, StringBuffer* #endif ); extern int sbputc( #ifdef __STDC__ int, StringBuffer* #endif ); extern char* sbflush( #ifdef __STDC__ StringBuffer* #endif ); extern int sbtell( #ifdef __STDC__ StringBuffer* #endif ); extern void sbrewind( #ifdef __STDC__ StringBuffer* #endif ); extern int sbseek( #ifdef __STDC__ StringBuffer*, int #endif ); /*----------------------------------------------------------------------------- ** Macro: sbputchar() ** Purpose: Put the character |C| into the string buffer |SB|. ** ** This macro is not sane. The arguments are expanded ** several times. Thus they must not contain side ** effects. ** Arguments: ** C Character to put. ** SB Destination string buffer. ** Returns: nothing **___________________________________________________ */ #define sbputchar(C,SB) ((SB)->sb__ptr < (SB)->sb__size \ ? (SB)->sb__string[(SB)->sb__ptr++] = C \ : sbputc(C,SB)) #endif BibTool/include/bibtool/stack.h0000644000175100017510000000276312646460546015410 0ustar genegene/*** stack.h ****************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module provides access to the functions defined in the ** module |stack.c|. The the documentation of this module for ** details. ** ******************************************************************************/ #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String pop_string _ARG((void)); /* stack.c */ void push_string _ARG((String s)); /* stack.c */ BibTool/include/bibtool/symbols.h0000644000175100017510000001136012646460553015762 0ustar genegene/*** symbols.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file contains definitions dealing with symbols. ** ** \BibTool{} uses symbols as the basic representation for ** strings. Symbols are stored in a symbol table and shared ** among different instances. Thus the same string occurring at ** different places has to be stored only once. ** ** Another advantage of symbols is that once you have got two ** symbols at hand it is rather easy to compare them for ** equality. A simple pointer comparison is enough. It is not ** necessary to compare them character by character. ** ** The disadvantage of a symbol is that you can not simply modify ** it temporarily since it is part of the symbol table. This ** symbol table would be in an insane state otherwise. Thus you ** always have to make a copy if you want to modify a symbol. ** ** The functions defined in |symbols.c| are exported with this ** header file as well. ** ******************************************************************************/ #ifndef SYMBOLS_H_LOADED #define SYMBOLS_H_LOADED #include /*----------------------------------------------------------------------------- ** Macro: symbol() ** Type: char * ** Purpose: Translate a string into a symbol. ** The symbol returned is either created or an existing ** symbol is returned. ** Arguments: ** STR String to translate into a symbol. ** Returns: The symbol corresponding to the argument. **___________________________________________________ */ #define symbol(STR) sym_add(STR,1) /*----------------------------------------------------------------------------- ** Macro: ReleaseSymbol() ** Type: void ** Purpose: The symbol given as argument is released. In fact the ** memory is not really freed but one instance is marked ** as not used any more. At other places the symbol might ** be still required. The freeing of memory is performed ** by the garbage collector |sym_gc()|. ** Arguments: ** SYM Symbol to release. ** Returns: nothing **___________________________________________________ */ #ifdef FREE_MEMORY #define ReleaseSymbol(SYM) sym_del(SYM) #else #define ReleaseSymbol(SYM) #endif /*****************************************************************************/ /*** ***/ /*****************************************************************************/ #define SYMBOL_STATIC 1 /*----------------------------------------------------------------------------- ** Variable: sym_empty ** Type: String ** Purpose: The empty symbol. This is a symbol pointing ** immediately to a |\0| byte. This needs ** |init_symbols()| to be called first. **___________________________________________________ */ extern String sym_empty; /*----------------------------------------------------------------------------- ** Variable: sym_crossref ** Type: String ** Purpose: The symbol |crossref|. This variable needs ** |init_symbols()| to be called first. **___________________________________________________ */ extern String sym_crossref; #define new_Ustring(S) (String)new_string((char*)(S)) #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String sym_add _ARG((String s,int count)); /* symbols.c */ String sym_extract _ARG((String ap,String ep,int count));/* symbols.c */ char * new_string _ARG((char * s)); /* symbols.c */ int sym_flag _ARG((String s)); /* symbols.c */ void init_symbols _ARG((void)); /* symbols.c */ void sym_dump _ARG((void)); /* symbols.c */ void sym_gc _ARG((void)); /* symbols.c */ void sym_set_flag _ARG((String s,int flags)); /* symbols.c */ void sym_unlink _ARG((String s)); /* symbols.c */ #endif /* SYMBOLS_H_LOADED */ BibTool/include/bibtool/tex_aux.h0000644000175100017510000000274612646460560015755 0ustar genegene/*** tex_aux.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #include #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int apply_aux _ARG((DB db)); /* tex_aux.c */ int foreach_aux _ARG((int (fct)_ARG((String)))); /* tex_aux.c */ int aux_used _ARG((String s)); /* tex_aux.c */ int read_aux _ARG((String fname,void (*fct)(char*),int verbose));/*tex_aux.c*/ void clear_aux _ARG((void)); /* tex_aux.c */ BibTool/include/bibtool/tex_read.h0000644000175100017510000000365012646460564016072 0ustar genegene/*** tex_read.h *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This header file provides definitions for the use of functions ** to immitate the reading apparatus of \TeX{} which are defined ** in |tex_read.c|. ** ******************************************************************************/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int TeX_read _ARG((String cp, String *sp)); /* tex-read.c */ void TeX_active _ARG((int c,int arity, String s));/* tex_read.c */ void TeX_close _ARG((void)); /* tex_read.c */ void TeX_def _ARG((String s)); /* tex_read.c */ void TeX_define _ARG((char *name,int arity,char *body));/* tex_read.c */ void TeX_open_file _ARG((FILE * file)); /* tex_read.c */ void TeX_open_string _ARG((String s)); /* tex_read.c */ void TeX_reset _ARG((void)); /* tex_read.c */ BibTool/include/bibtool/type.h0000644000175100017510000004127312646460570015260 0ustar genegene/*** type.h ******************************************************************* ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** Description: ** This module is a replacement for the system header file ** |ctype.h|. In contrast to some implementations of the |isalpha| ** and friends the macros in this header are stable. This means ** that the argument is evaluated exactly once and each macro ** consists of exactly one C statement. Thus these macros can ** be used even at those places where only a single statement is ** allowed (conditionals without braces) or with arguments ** containing side effects. ** ** In addition this is a starting point to implement an xord ** array like \TeX{} has one (some day\dots) ** ** This header file requires the initialization function ** |init_type()| to be called before the macros will work as ** described. ** ** This header file also provides the functions and varaibles ** defined in |type.c| ** ******************************************************************************/ #ifndef TYPE_H #define TYPE_H #include typedef unsigned char Uchar; typedef Uchar* String; #define StringNULL (String)NULL #define T__None 0 #define T__Upper 1 #define T__Lower 2 #define T__Allowed 4 #define T__Number 8 #define T__Space 16 #define T__Extended 32 #define T__WordSep 64 #ifdef INIT_TYPE int type__allowed[257] = { /*0 */ T__None, /*1 */ T__Space|T__WordSep, /*2 */ T__Space|T__WordSep, /*3 */ T__Space|T__WordSep, /*4 */ T__Space|T__WordSep, /*5 */ T__Space|T__WordSep, /*6 */ T__Space|T__WordSep, /*7 */ T__Space|T__WordSep, /*8 */ T__Space|T__WordSep, /*9 */ T__Space|T__WordSep, /*a */ T__Space|T__WordSep, /*b */ T__Space|T__WordSep, /*c */ T__Space|T__WordSep, /*d */ T__Space|T__WordSep, /*e */ T__Space|T__WordSep, /*f */ T__Space|T__WordSep, /*0 */ T__Space|T__WordSep, /*1 */ T__Space|T__WordSep, /*2 */ T__Space|T__WordSep, /*3 */ T__Space|T__WordSep, /*4 */ T__Space|T__WordSep, /*5 */ T__Space|T__WordSep, /*6 */ T__Space|T__WordSep, /*7 */ T__Space|T__WordSep, /*8 */ T__Space|T__WordSep, /*9 */ T__Space|T__WordSep, /*a */ T__Space|T__WordSep, /*b */ T__Space|T__WordSep, /*c */ T__Space|T__WordSep, /*d */ T__Space|T__WordSep, /*e */ T__Space|T__WordSep, /*f */ T__Space|T__WordSep, /*0 */ T__Space|T__WordSep, /*1 ! */ T__Allowed|T__WordSep, /*2 " */ T__None, /*3 # */ T__None, /*4 $ */ T__Allowed, /*5 % */ T__None, /*6 & */ T__Allowed, /*7 ' */ T__None, /*8 ( */ T__None, /*9 ) */ T__None, /*a * */ T__Allowed, /*b + */ T__Allowed, /*c , */ T__None|T__WordSep, /*d - */ T__Allowed, /*e . */ T__Allowed|T__WordSep, /*f / */ T__Allowed, /*0 0 */ T__Allowed|T__Number, /*1 1 */ T__Allowed|T__Number, /*2 2 */ T__Allowed|T__Number, /*3 3 */ T__Allowed|T__Number, /*4 4 */ T__Allowed|T__Number, /*5 5 */ T__Allowed|T__Number, /*6 6 */ T__Allowed|T__Number, /*7 7 */ T__Allowed|T__Number, /*8 8 */ T__Allowed|T__Number, /*9 9 */ T__Allowed|T__Number, /*a : */ T__Allowed|T__WordSep, /*b ; */ T__Allowed|T__WordSep, /*c < */ T__Allowed, /*d = */ T__None, /*e > */ T__Allowed, /*f ? */ T__Allowed, /*0 @ */ T__Allowed|T__WordSep, /*1 A */ T__Allowed|T__Upper, /*2 B */ T__Allowed|T__Upper, /*3 C */ T__Allowed|T__Upper, /*4 D */ T__Allowed|T__Upper, /*5 E */ T__Allowed|T__Upper, /*6 F */ T__Allowed|T__Upper, /*7 G */ T__Allowed|T__Upper, /*8 H */ T__Allowed|T__Upper, /*9 I */ T__Allowed|T__Upper, /*a J */ T__Allowed|T__Upper, /*b K */ T__Allowed|T__Upper, /*c L */ T__Allowed|T__Upper, /*d M */ T__Allowed|T__Upper, /*e N */ T__Allowed|T__Upper, /*f O */ T__Allowed|T__Upper, /*0 P */ T__Allowed|T__Upper, /*1 Q */ T__Allowed|T__Upper, /*2 R */ T__Allowed|T__Upper, /*3 S */ T__Allowed|T__Upper, /*4 T */ T__Allowed|T__Upper, /*5 U */ T__Allowed|T__Upper, /*6 V */ T__Allowed|T__Upper, /*7 W */ T__Allowed|T__Upper, /*8 X */ T__Allowed|T__Upper, /*9 Y */ T__Allowed|T__Upper, /*a Z */ T__Allowed|T__Upper, /*b [ */ T__Allowed, /*c \ */ T__Allowed, /*d ] */ T__Allowed, /*e ^ */ T__Allowed, /*f _ */ T__Allowed, /*0 ` */ T__Allowed, /*1 a */ T__Allowed|T__Lower, /*2 b */ T__Allowed|T__Lower, /*3 c */ T__Allowed|T__Lower, /*4 d */ T__Allowed|T__Lower, /*5 e */ T__Allowed|T__Lower, /*6 f */ T__Allowed|T__Lower, /*7 g */ T__Allowed|T__Lower, /*8 h */ T__Allowed|T__Lower, /*9 i */ T__Allowed|T__Lower, /*a j */ T__Allowed|T__Lower, /*b k */ T__Allowed|T__Lower, /*c l */ T__Allowed|T__Lower, /*d m */ T__Allowed|T__Lower, /*e n */ T__Allowed|T__Lower, /*f o */ T__Allowed|T__Lower, /*0 p */ T__Allowed|T__Lower, /*1 q */ T__Allowed|T__Lower, /*2 r */ T__Allowed|T__Lower, /*3 s */ T__Allowed|T__Lower, /*4 t */ T__Allowed|T__Lower, /*5 u */ T__Allowed|T__Lower, /*6 v */ T__Allowed|T__Lower, /*7 w */ T__Allowed|T__Lower, /*8 x */ T__Allowed|T__Lower, /*9 y */ T__Allowed|T__Lower, /*a z */ T__Allowed|T__Lower, /*b { */ T__None, /*c | */ T__Allowed, /*d } */ T__None, /*e ~ */ T__WordSep, /*f */ T__Allowed, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended, /*0 */ T__Allowed|T__Extended, /*1 */ T__Allowed|T__Extended, /*2 */ T__Allowed|T__Extended, /*3 */ T__Allowed|T__Extended, /*4 */ T__Allowed|T__Extended, /*5 */ T__Allowed|T__Extended, /*6 */ T__Allowed|T__Extended, /*7 */ T__Allowed|T__Extended, /*8 */ T__Allowed|T__Extended, /*9 */ T__Allowed|T__Extended, /*a */ T__Allowed|T__Extended, /*b */ T__Allowed|T__Extended, /*c */ T__Allowed|T__Extended, /*d */ T__Allowed|T__Extended, /*e */ T__Allowed|T__Extended, /*f */ T__Allowed|T__Extended }; /*----------------------------------------------------------------------------- ** Variable: trans_lower ** Type: char* ** Purpose: Translation table mapping upper case letters to lower ** case. Such a translation table can be used as argument ** to the regular expression functions. **___________________________________________________ */ Uchar trans_lower[256]; /* */ /*----------------------------------------------------------------------------- ** Variable: trans_upper ** Type: char* ** Purpose: Translation table mapping lower case letters to upper ** case. Such a translation table can be used as argument ** to the regular expression functions. **___________________________________________________ */ Uchar trans_upper[256]; /* */ /*----------------------------------------------------------------------------- ** Variable: trans_id ** Type: char* ** Purpose: Translation table performing no translation. Thus it ** implements the identity a translation table can be ** used as argument to the regular expression functions. **___________________________________________________ */ Uchar trans_id[256]; /* */ #else extern int type__allowed[]; extern Uchar trans_lower[256]; extern Uchar trans_upper[256]; extern Uchar trans_id[256]; #endif /*----------------------------------------------------------------------------- ** Macro: is_allowed() ** Type: int ** Purpose: Decide whether the character given as argument is an ** allowed character in the sense of \BibTeX. ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the argument is an allowed character. **___________________________________________________ */ #define is_allowed(C) (type__allowed[(Uchar)C]&T__Allowed) /*----------------------------------------------------------------------------- ** Macro: is_upper() ** Type: int ** Purpose: Decide whether the character given as argument is a ** upper case letter. ** (Characters outside the ASCII range are not considered ** letters yet) ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the character is an uppercase letter. **___________________________________________________ */ #define is_upper(C) (type__allowed[(Uchar)C]&T__Upper) /*----------------------------------------------------------------------------- ** Macro: is_lower() ** Type: int ** Purpose: Decide whether the character given as argument is a ** lower case letter. ** (Characters outside the ASCII range are not considered ** letters yet) ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the character is a lowercase letter. **___________________________________________________ */ #define is_lower(C) (type__allowed[(Uchar)C]&T__Lower) /*----------------------------------------------------------------------------- ** Macro: is_alpha() ** Type: int ** Purpose: Decide whether the character given as argument is a ** letter. ** (Characters outside the ASCII range are not considered ** letters yet) ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the character is a letter. **___________________________________________________ */ #define is_alpha(C) (type__allowed[(Uchar)C]&(T__Upper|T__Lower)) /*----------------------------------------------------------------------------- ** Macro: is_digit() ** Type: int ** Purpose: Decide whether the character given as argument is a ** digit. ** (Characters outside the ASCII range are not considered ** letters yet) ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the character is a digit. **___________________________________________________ */ #define is_digit(C) (type__allowed[(Uchar)C]&T__Number) /*----------------------------------------------------------------------------- ** Macro: is_space() ** Type: int ** Purpose: Decide whether the character given as argument is a ** space character. |'\0'| is not a space character. ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the character is a space character. **___________________________________________________ */ #define is_space(C) (type__allowed[(Uchar)C]&T__Space) /*----------------------------------------------------------------------------- ** Macro: is_extended() ** Type: int ** Purpose: Decide whether the character given as argument is an ** extended character outside the ASCII range. ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the character is an extended character. **___________________________________________________ */ #define is_extended(C) (type__allowed[(Uchar)C]&T__Extended) /*----------------------------------------------------------------------------- ** Macro: is_wordsep() ** Type: int ** Purpose: Decide whether the character given as argument is a ** word separator which denotes no word constituent. ** Arguments: ** C Character to consider ** Returns: |TRUE| iff the character is a word separator. **___________________________________________________ */ #define is_wordsep(C) (type__allowed[(Uchar)C]&T__WordSep) /*----------------------------------------------------------------------------- ** Macro: ToLower() ** Type: char ** Purpose: Translate a character to it's lower case dual. If the ** character is no upper case letter then the character ** is returned unchanged. ** Arguments: ** C Character to translate ** Returns: The lower case letter or the character itself. **___________________________________________________ */ #define ToLower(C) trans_lower[(Uchar)(C)] /*----------------------------------------------------------------------------- ** Macro: ToUpper() ** Type: char ** Purpose: Translate a character to it's upper case dual. If the ** character is no lower case letter then the character ** is returned unchanged. ** Arguments: ** C Character to translate ** Returns: The upper case letter or the character itself. **___________________________________________________ */ #define ToUpper(C) trans_upper[(Uchar)(C)] #define SYMBOL_TYPE_LOWER 0 #define SYMBOL_TYPE_UPPER 1 #define SYMBOL_TYPE_CASED 2 #endif #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif String lower _ARG((String s)); /* type.c */ int case_cmp _ARG((String s, String t)); /* type.c */ void add_word_sep _ARG((String s)); /* type.c */ void init_type _ARG((void)); /* type.c */ BibTool/include/bibtool/version.h0000644000175100017510000000241712646460600015753 0ustar genegene/*** version.h **************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ extern char * bibtool_version; #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif void show_version _ARG((void)); /* version.c */ /*---------------------------------------------------------------------------*/ BibTool/include/bibtool/wordlist.h0000644000175100017510000000635312646460604016144 0ustar genegene/*** wordlist.h *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ #ifndef WordNULL #include /*----------------------------------------------------------------------------- ** Typedef: WordList ** Purpose: This data type represents a node in a list of ** strings. This list only provides a next pointer. and ** is prety generic. **________________________________________________ */ typedef struct wORDlIST /* */ { String wl_word; /* String value of */ /* this node. */ struct wORDlIST *wl_next; /* Pointer to the next */ /* node. */ } SWordList, *WordList; /* */ /*----------------------------------------------------------------------------- ** Constant: WordNULL() ** Type: WordList ** Purpose: This is the |NULL| value for a |WordList|. It ** terminates the list and represents the empty node. ** Returns: |NULL| of appropriate type. **___________________________________________________ */ #define WordNULL ((WordList)0) /*----------------------------------------------------------------------------- ** Macro: ThisWord() ** Type: String ** Purpose: This macro returns the string of a |WordList| node. ** Arguments: ** WL |WordList| to consider which is not |WordNULL|. ** Returns: The word stored in this node. **___________________________________________________ */ #define ThisWord(WL) ((WL)->wl_word) /*----------------------------------------------------------------------------- ** Macro: NextWord() ** Type: WordList ** Purpose: This macro returns the next |WordList| node of a given ** |WordList| if this is not |WordNULL|. ** Arguments: ** WL |WordList| to consider which is not |WordNULL|. ** Returns: The next |WordList|. **___________________________________________________ */ #define NextWord(WL) ((WL)->wl_next) #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif int find_word _ARG((String s, WordList wl)); /* wordlist.c */ int foreach_word _ARG((WordList wl,int (*fct)_ARG((String))));/* wordlist.c */ void free_words _ARG((WordList *wlp,void (*fct)_ARG((String))));/* wordlist.c*/ void add_word _ARG((String s,WordList *wlp)); /* wordlist.c */ #endif BibTool/lib/biblatex.rsc0000644000175100017510000002250712646461472014123 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 2012-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Entry types for bibLaTeX % new.entry.type{Article} new.entry.type{Book} new.entry.type{MVBook} new.entry.type{InBook} new.entry.type{BookInBook} new.entry.type{SuppBook} new.entry.type{Booklet} new.entry.type{Collection} new.entry.type{MVCollection} new.entry.type{InCollection} new.entry.type{SuppCollection} new.entry.type{Manual} new.entry.type{Misc} new.entry.type{Online} new.entry.type{Patent} new.entry.type{Periodical} new.entry.type{SuppPeriodical} new.entry.type{Proceedings} new.entry.type{MVProceedings} new.entry.type{Reference} new.entry.type{MVReference} new.entry.type{Inreference} new.entry.type{Report} new.entry.type{Set} new.entry.type{Thesis} new.entry.type{Unpublished} new.entry.type{Cdata} new.entry.type{CustomA} new.entry.type{CustomB} new.entry.type{CustomC} new.entry.type{CustomD} new.entry.type{CustomE} new.entry.type{CustomF} new.entry.type{Conference} new.entry.type{Electronic} new.entry.type{MasterThesis} new.entry.type{PhdThesis} new.entry.type{TechReport} new.entry.type{WWW} new.entry.type{Artwork} new.entry.type{Audio} new.entry.type{BibNote} new.entry.type{Commentary} new.entry.type{Image} new.entry.type{Jurisdiction} new.entry.type{Legislation} new.entry.type{Legal} new.entry.type{Letter} new.entry.type{Movie} new.entry.type{Music} new.entry.type{Performance} new.entry.type{Review} new.entry.type{Software} new.entry.type{Standard} new.entry.type{Video} % % Field capitalization for bibLaTeX % % special fields new.field.type { entryset = EntrySet } new.field.type { entrysubtype = EntrySubtype } new.field.type { execute = Execute } new.field.type { hyphenation = Hyphenation } new.field.type { keywords = Keywords } new.field.type { label = Label } new.field.type { options = Options } new.field.type { presort = Presort } new.field.type { shorthand = Shorthand } new.field.type { sortkey = SortKey } new.field.type { sortname = SortName } new.field.type { sorttitle = SortTitle } new.field.type { sortyear = SortYear } new.field.type { crossref = CrossRef } new.field.type { xdata = XData } new.field.type { xref = XRef } % data fields new.field.type { abstract = Abstract } new.field.type { addendum = Addendum } new.field.type { address = Address } new.field.type { afterword = Afterword } new.field.type { annotation = Annotation } new.field.type { annote = Annote } new.field.type { annotator = Annotator } new.field.type { author = Author } new.field.type { authortype = AuthorType } new.field.type { bookauthor = BookAuthor } new.field.type { booksubtitle = BookSubtitle } new.field.type { booktitle = BookTitle } new.field.type { booktitleaddon = BookTitleAddOn } new.field.type { chapter = Chapter } new.field.type { commentator = Commentator } new.field.type { date = Date } new.field.type { doi = DOI } new.field.type { edition = Edition } new.field.type { editor = Editor } new.field.type { editora = EditorA } new.field.type { editorb = EditorB } new.field.type { editorc = EditorC } new.field.type { editortype = EditorType } new.field.type { editoratype = EditorAType } new.field.type { editorbtype = EditorBType } new.field.type { editorctype = EditorCType } new.field.type { eid = EID } new.field.type { eprint = EPrint } new.field.type { eprintclass = EPrintClass } new.field.type { eprinttype = EPrintType } new.field.type { eventdate = EventDate } new.field.type { eventtitle = EventTitle } new.field.type { file = File } new.field.type { foreword = Foreword } new.field.type { gender = Gender } new.field.type { howpublished = HowPublished } new.field.type { indexsorttitle = IndexSortTitle } new.field.type { indextitle = IndexTitle } new.field.type { institution = Institution } new.field.type { introduction = Introduction } new.field.type { isan = ISAN } new.field.type { isbn = ISBN } new.field.type { ismn = ISMN } new.field.type { isrn = ISRN } new.field.type { issn = ISSN } new.field.type { issue = Issue } new.field.type { issuetitle = IssueTitle } new.field.type { issuesubtitle = IssueSubtitle } new.field.type { iswc = ISWC } new.field.type { journal = Journal } new.field.type { journaltitle = JournalTitle } new.field.type { journalsubtitle = JournalSubtitle } new.field.type { language = Language } new.field.type { library = Library } new.field.type { location = Location } new.field.type { bookpagination = BookPagination } new.field.type { mainsubtitle = MainSubtitle } new.field.type { maintitle = MainTitle } new.field.type { maintitleaddon = MainTitleAddOn } new.field.type { month = Month } new.field.type { nameaddon = NameAddOn } new.field.type { note = Note } new.field.type { number = Number } new.field.type { organization = Organization } new.field.type { origlanguage = OrigLanguage } new.field.type { origlocation = OrigLocation } new.field.type { origpublisher = OrigPublisher } new.field.type { origtitle = OrigTitle } new.field.type { origdate = OrigDate } new.field.type { pages = Pages } new.field.type { pagetotal = PageTotal } new.field.type { pagination = Pagination } new.field.type { part = Part } new.field.type { pdf = PDF } new.field.type { pubstate = PubState } new.field.type { reprinttitle = ReprintTitle } new.field.type { holder = Holder } new.field.type { publisher = Publisher } new.field.type { school = School } new.field.type { series = Series } new.field.type { shortauthor = ShortAuthor } new.field.type { shorteditor = ShortEditor } new.field.type { shorthandintro = ShorthandIntro } new.field.type { shortjournal = ShortJournal } new.field.type { shortseries = ShortSeries } new.field.type { shorttitle = ShortTitle } new.field.type { subtitle = Subtitle } new.field.type { title = Title } new.field.type { titleaddon = TitleAddOn } new.field.type { translator = Translator } new.field.type { type = Type } new.field.type { url = URL } new.field.type { urldate = URLDate } new.field.type { venue = Venue } new.field.type { version = Version } new.field.type { volume = Volume } new.field.type { volumes = Volumes } new.field.type { year = Year } % aliases new.field.type { archiveprefix = ArchivePrefix } new.field.type { primaryclass = PrimaryClass } % custom fields new.field.type { namea = NameA } new.field.type { nameb = NameB } new.field.type { namec = NameC } new.field.type { nameatype = NameAType } new.field.type { namebtype = NameBType } new.field.type { namectype = NameCType } new.field.type { lista = ListA } new.field.type { listb = ListB } new.field.type { listc = ListC } new.field.type { listd = ListD } new.field.type { liste = ListE } new.field.type { listf = ListF } new.field.type { usera = UserA } new.field.type { userb = UserB } new.field.type { userc = UserC } new.field.type { userd = UserD } new.field.type { usere = UserE } new.field.type { userf = UserF } new.field.type { verba = VerbA } new.field.type { verbb = VerbB } new.field.type { verbc = VerbC } BibTool/lib/braces.rsc0000644000175100017510000000243012646461501013552 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Translate double quotes as delimiters "" by braces {} % rewrite.rule { "^\"\([^#]*\)\"$" = "{\1}" } rewrite.rule { "# \"\([^#]*\)\"$" = "# {\1}" } rewrite.rule { "^\"\([^#]*\)\" #" = "{\1} #" } rewrite.rule { "# \"\([^#]*\)\" #" = "# {\1} #" } BibTool/lib/check_y.rsc0000644000175100017510000000247712646461507013741 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Semantic checks for year fields % check.rule { year "^[\"{]?[0-9][0-9][\"}]?$" } check.rule { year "^[\"{]?1[89][0-9][0-9][\"}]?$" } check.rule { year "^[\"{]?20[0-9][0-9][\"}]?$" } check.rule { year "" "\@ \$: Semantic error. Year has to be a suitable number" } BibTool/lib/default.rsc0000644000175100017510000001006512646461514013746 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1996-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Default resource file % You don't need this file. The settings defined here are also compiled into % BibTool. This file can serve as a basis for your own modifications. % The values are taken from the UNIX installation. % bibtex.env.name = "BIBINPUTS" check.case.sensitive = on check.double = off check.double.delete = off count.all = off count.used = off crossref.limit = 32 default.key = "**key*" dir.file.separator = "/" env.separator = ":" expand.macros = on fmt.et.al = ".ea" fmt.inter.name = "-" fmt.name.name = "." fmt.name.pre = "." fmt.name.title = ":" fmt.title.title = "-" ignored.word = "a" ignored.word = "an" ignored.word = "the" ignored.word = "le" ignored.word = "les" ignored.word = "la" ignored.word = "un" ignored.word = "une" ignored.word = "el" ignored.word = "il" ignored.word = "der" ignored.word = "die" ignored.word = "das" ignored.word = "ein" ignored.word = "eine" key.base = lower key.expand.macros = on key.format = short key.generation = off key.number.separator = "*" new.entry.type = "Article" new.entry.type = "Book" new.entry.type = "Booklet" new.entry.type = "Conference" new.entry.type = "InBook" new.entry.type = "InCollection" new.entry.type = "InProceedings" new.entry.type = "Manual" new.entry.type = "MastersThesis" new.entry.type = "Misc" new.entry.type = "PhDThesis" new.entry.type = "Proceedings" new.entry.type = "TechReport" new.entry.type = "Unpublished" pass.comments = off preserve.key.case = off preserve.keys = off print.align = 18 print.align.string = 18 print.align.preamble = 11 print.align.comment = 10 print.align.key = 18 print.all.strings = on print.braces = on print.comma.at.end = on print.deleted.prefix = "###" print.deleted.entries = on print.entry.types = "pisnmac" print.equal.right = on print.indent = 2 print.line.length = 77 print.newline = 1 print.parentheses = off print.use.tab = on print.wide.equal = off quiet = off rewrite.case.sensitive = on rewrite.limit = 512 select.crossrefs = off select.case.sensitive = off select.fields = "$key" sort = off sort.cased = off sort.format = "%s($key)" sort.macros = on sort.reverse = off suppress.initial.newline = off symbol.type = lower verbose = off BibTool/lib/field.rsc0000644000175100017510000000410512646461525013405 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Field capitalization % new.field.type { address = Address } new.field.type { author = Author } new.field.type { booktitle = Booktitle } new.field.type { chapter = Chapter } new.field.type { edition = Edition } new.field.type { editor = Editor } new.field.type { howpublished = Howpublished } new.field.type { institution = Institution } new.field.type { journal = Journal } new.field.type { key = Key } new.field.type { month = Month } new.field.type { note = Note } new.field.type { number = Number } new.field.type { organization = Organization } new.field.type { pages = Pages } new.field.type { publisher = Publisher } new.field.type { school = School } new.field.type { series = Series } new.field.type { title = Title } new.field.type { type = Type } new.field.type { volume = Volume } new.field.type { year = Year } BibTool/lib/improve.rsc0000644000175100017510000000251012646461532013777 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Style Impovements. % % delete empty fields rewrite.rule {"^\" *\"$"} rewrite.rule {"^{ *}$"} % correct page ranges rewrite.rule {pages # "\([0-9]+\) *\(-\|---\) *\([0-9]+\)" = "\1--\3"} % delete delimiters if the field is purely numerical rewrite.rule {"^[\"{] *\([0-9]+\) *[\"}]$" "\1"} BibTool/lib/iso2tex.rsc0000644000175100017510000001042112646461536013717 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Translation of ISO 8859/1 characters to BibTeX equivalents % rewrite.rule { "¡" # "!`" } %rewrite.rule { "¢" # "{\\cent}" } %rewrite.rule { "£" # "{\\pounds}" } %rewrite.rule { "¤" # "{\\currency}" } %rewrite.rule { "¥" # "{\\yen}" } %rewrite.rule { "¦" # "{\\MiD}" } rewrite.rule { "§" # "{\\S}" } %rewrite.rule { "¨" # "{\\\"{}}" } %rewrite.rule { "©" # "{\\copyright}" } %rewrite.rule { "ª" # "{\\OIfem}" } %rewrite.rule { "«" # "\\ll " } %rewrite.rule { "¬" # "\\neg " } %rewrite.rule { "­" # "\\-" } %rewrite.rule { "®" # "{\\Registered}" } %rewrite.rule { "¯" # "{\\macron}" } %rewrite.rule { "°" # "{\\degree}" } %rewrite.rule { "±" # "\\pm " } %rewrite.rule { "²" # "\\SuperTwo " } %rewrite.rule { "³" # "\\SuperThree " } %rewrite.rule { "´" # "{\\'{}}" } %rewrite.rule { "µ" # "\\mu " } rewrite.rule { "¶" # "{\\P}" } %rewrite.rule { "·" # "\\cdot " } %rewrite.rule { "¸" # "{\\c{}}" } %rewrite.rule { "¹" # "\\SuperOne " } %rewrite.rule { "º" # "{\\OImasc}" } %rewrite.rule { "»" # "\\gg " } %rewrite.rule { "¼" # "\\OneQuater " } %rewrite.rule { "½" # "\\OneHalf " } %rewrite.rule { "¾" # "\\ThreeQuaters " } rewrite.rule { "¿" # "?`" } rewrite.rule { "À" # "{\\`A}" } rewrite.rule { "Á" # "{\\'A}" } rewrite.rule { "Â" # "{\\^A}" } rewrite.rule { "Ã" # "{\\~A}" } rewrite.rule { "Ä" # "{\\\"A}" } rewrite.rule { "Å" # "{\\AA}" } rewrite.rule { "Æ" # "{\\AE}" } rewrite.rule { "Ç" # "{\\c{C}}" } rewrite.rule { "È" # "{\\`E}" } rewrite.rule { "É" # "{\\'E}" } rewrite.rule { "Ê" # "{\\^E}" } rewrite.rule { "Ë" # "{\\\"E}" } rewrite.rule { "Ì" # "{\\`I}" } rewrite.rule { "Í" # "{\\'I}" } rewrite.rule { "Î" # "{\\^I}" } rewrite.rule { "Ï" # "{\\\"I}" } %rewrite.rule { "Ð" # "{\\Dstroke}" } rewrite.rule { "Ñ" # "{\\~N}" } rewrite.rule { "Ò" # "{\\`O}" } rewrite.rule { "Ó" # "{\\'O}" } rewrite.rule { "Ô" # "{\\^O}" } rewrite.rule { "Õ" # "{\\~O}" } rewrite.rule { "Ö" # "{\\\"O}" } %rewrite.rule { "×" # "\\times " } rewrite.rule { "Ø" # "{\\O}" } rewrite.rule { "Ù" # "{\\`U}" } rewrite.rule { "Ú" # "{\\'U}" } rewrite.rule { "Û" # "{\\^U}" } rewrite.rule { "Ü" # "{\\\"U}" } rewrite.rule { "Ý" # "{\\'Y}" } %rewrite.rule { "Þ" # "{\\Thorn}" } rewrite.rule { "ß" # "{\\ss}" } rewrite.rule { "à" # "{\\`a}" } rewrite.rule { "á" # "{\\'a}" } rewrite.rule { "â" # "{\\^a}" } rewrite.rule { "ã" # "{\\~a}" } rewrite.rule { "ä" # "{\\\"a}" } rewrite.rule { "å" # "{\\aa}" } rewrite.rule { "æ" # "{\\ae}" } rewrite.rule { "ç" # "{\\c{c}}" } rewrite.rule { "è" # "{\\`e}" } rewrite.rule { "é" # "{\\'e}" } rewrite.rule { "ê" # "{\\^e}" } rewrite.rule { "ë" # "{\\\"e}" } rewrite.rule { "ì" # "{\\`\\i}" } rewrite.rule { "í" # "{\\'\\i}" } rewrite.rule { "î" # "{\\^\\i}" } rewrite.rule { "ï" # "{\\\"\\i}" } %rewrite.rule { "ð" # "{\\dstroke}" } rewrite.rule { "ñ" # "{\\~n}" } rewrite.rule { "ò" # "{\\`o}" } rewrite.rule { "ó" # "{\\'o}" } rewrite.rule { "ô" # "{\\^o}" } rewrite.rule { "õ" # "{\\~o}" } rewrite.rule { "ö" # "{\\\"o}" } %rewrite.rule { "÷" # "{\\div}" } rewrite.rule { "ø" # "{\\o}" } rewrite.rule { "ù" # "{\\`u}" } rewrite.rule { "ú" # "{\\'u}" } rewrite.rule { "û" # "{\\^u}" } rewrite.rule { "ü" # "{\\\"u}" } rewrite.rule { "ý" # "{\\'y}" } %rewrite.rule { "þ" # "{\\thorn}" } rewrite.rule { "ÿ" # "{\\\"y}" } BibTool/lib/month.rsc0000644000175100017510000000450012646461542013445 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % This resource file tries to introduce BibTeX strings for month names. % Provisions are made to preserve other information contained in the % month field. % rewrite.rule { month = "^[\"{] *\(.*\)january\(.*\) *[\"}]$" # "{\1} # jan # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)february\(.*\) *[\"}]$" # "{\1} # feb # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)march\(.*\) *[\"}]$" # "{\1} # mar # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)april\(.*\) *[\"}]$" # "{\1} # apr # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)may\(.*\) *[\"}]$" # "{\1} # may # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)june\(.*\) *[\"}]$" # "{\1} # jun # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)july\(.*\) *[\"}]$" # "{\1} # jul # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)august\(.*\) *[\"}]$" # "{\1} # aug # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)september\(.*\) *[\"}]$" # "{\1} # sep # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)october\(.*\) *[\"}]$" # "{\1} # oct # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)november\(.*\) *[\"}]$" # "{\1} # nov # {\2}" } rewrite.rule { month = "^[\"{] *\(.*\)december\(.*\) *[\"}]$" # "{\1} # dec # {\2}" } rewrite.rule { month = "^{ *} # " = ""} rewrite.rule { month = " # { *}$" = ""} BibTool/lib/opt.rsc0000644000175100017510000000420012646461547013124 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Optimizations % new.field.type { OPTaddress = Address } new.field.type { OPTauthor = Author } new.field.type { OPTbooktitle = Booktitle } new.field.type { OPTchapter = Chapter } new.field.type { OPTedition = Edition } new.field.type { OPTeditor = Editor } new.field.type { OPThowpublished = Howpublished } new.field.type { OPTinstitution = Institution } new.field.type { OPTjournal = Journal } new.field.type { OPTkey = Key } new.field.type { OPTmonth = Month } new.field.type { OPTnote = Note } new.field.type { OPTnumber = Number } new.field.type { OPTorganization = Organization } new.field.type { OPTpages = Pages } new.field.type { OPTpublisher = Publisher } new.field.type { OPTschool = School } new.field.type { OPTseries = Series } new.field.type { OPTtitle = Title } new.field.type { OPTtype = Type } new.field.type { OPTvolume = Volume } new.field.type { OPTyear = Year } BibTool/lib/sort_fld.rsc0000644000175100017510000000513712646461554014146 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Sort order for fields % sort.order{article = author #title #journal #year #volume #number #pages #month #note } sort.order{book = author #editor #title #publisher #year #volume #series #address #edition #month #note} sort.order{booklet = author #title #howpublished #address #month #year #note} sort.order{conference = author #title #editor #booktitle #year #series #volume #pages #address #month #organization #publisher #note} sort.order{inproceedings = author #title #editor #booktitle #year #series #volume #pages #address #month #organization #publisher #note} sort.order{inbook = author #editor #title #chapter #pages #publisher #year #volume #number #series #type #address #edition #month #note} sort.order{incollection= author #title #editor #booktitle #publisher #year #volume #number #series #type #chapter #pages #address #edition #month #note} sort.order{manual= author #title #organization #address #edition #month #year #note } sort.order{mastersthesis= author #title #school #year #type #address #month #note} sort.order{misc= author #title #howpublished #year #month #note} sort.order{phdthesis = author #title #school #year #type #address #month #note } sort.order{proceedings = title #year #editor #volume #number #series #address #month #organization #publisher #note} sort.order{techreport = author #title #institution #year #type #number #address #month #note} sort.order{unpublished = author #title #year #month #note} BibTool/lib/tex_def.rsc0000644000175100017510000000264612646461560013747 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; either version 2, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Useful translations % tex.define {\"[1]=#1e} tex.define {\ss=ss} tex.define {\AE=AE} tex.define {\OE=OE} tex.define {\aa=aa} tex.define {\AA=AA} tex.define {\o=o} tex.define {\O=O} tex.define {\l=l} tex.define {\L=L} tex.define {\i=i} tex.define {\j=j} tex.define {\TeX=TeX} tex.define {\LaTeX=LaTeX} tex.define {\LaTeXe=LaTeX2e} tex.define {\BibTeX=BibTeX} tex.define {\AMSTeX=AMSTeX} BibTool/doc/bibtool.10000644000175100017510000001060212646422467013325 0ustar genegene.TH BIBTOOL 1 local .SH NAME BibTool \- BibTeX file manipulation tool .SH SYNOPSIS .B bibtool [options] [files] .SH DESCRIPTION This manual is not meant to be exhaustive. The complete documentation for .B BibTool can be found in the .IR "BibTool Manual" . BibTeX provides an easy to use means to integrate citations and bibliographies into LaTeX documents. But the user is left alone with the management of the BibTeX files. .B BibTool is intended to fill this gap. .B BibTool allows the manipulation of BibTeX files which goes beyond the possibilities - and intentions - of BibTeX. .PP .B BibTool manipulates BibTeX database files through the command line front\-end .B bibtool which accepts numerous options. Modifications are performed through resource instructions that allow the modification of the various internal parameters determining the behavior of .BR BibTool ; resource instructions can be grouped in resource files. The original .B BibTool distribution contains a sufficient set of resource file samples to perform basic, relevant manipulations. .SH OPTIONS .B bibtool accepts the following options. .SS "Resource files" .TP \fB\-R\fR Immediately evaluate the instructions from the default resource file. .TP .BI \fB\-r\ rsc_file Immediately evaluate the instructions from the resource file .IR rsc_file . .TP .BI \fB\-\-\ rsc_cmd Evaluate the resource instruction .IR rsc_cmd . .SS "Input file" .TP .BI \fB\-i\ bib_file Add the BibTeX database file .IR bib_file to the list of input files. If \fB\-i\fR omitted the file name may not start with a \-. If absent stdin is taken to read from. .\"Multiple input files may be given. Input files should follow the .BR bibtex (1) conventions. .SS "Output file" .TP .BI \fB\-o\ output_file Direct output to the file .IR output_file . If absent the output is directed to stdout. .SS "Status reporting" .TP \fB\-q\fR Suppress warnings. Errors can not be suppressed. .TP \fB\-v\fR Enable informative messages on the activities of BibTool. .SS "Sorting" .TP \fB\-s\fR Enable sorting of entries. .TP \fB\-S\fR Enable sorting of entries in reverse order. .TP .BI \fB\-A\ type Determine key disambuguation; .IR type in 0, a, A. .SS "Selecting items" .TP .BI \fB\-x\ aux_file Extract the entries from the auxiliary .RI ( .aux ) .\".BR latex (1) LaTeX .IR aux_file file. .TP .BI \fB\-X\ regex Select certain entries according to the regular expression .IR regex . .TP \fB\-c\fR Turn on the additional selection of crossreferenced entries. .SS "Key generation" .TP .BI \fB\-f\ key_format Set the specification for key generation to .IR key_format . .TP \fB\-F\fR Turn on key generation. .TP \fB\-k\fR Generate short format keys. .TP \fB\-K\fR Generate long format keys. .SS "Semantic checks" .TP \fB\-d\fR Find and mark (or delete) entries with identical sort keys. .SS "Strings/Macros" .TP .BI \fB\-m\ mac_file Write the macro definitions to the file .IR mac_file (\- is stdout). .TP .BI \fB\-M\ mac_file Write the used macro definitions to the file .IR mac_file (\- is stdout). .SS "Getting help" .TP \fB\-h\fR Print short help and exit. .TP \fB\-V\fR Print version and exit. .SS "Statistics" .TP \fB\-#\fR Print statistics about all known entry types (long). .TP \fB\-@\fR Print statistics about the used entry types only (short). .SH ENVIRONMENT .TP .B BIBINPUTS Search path for BibTeX database .RI ( .bib ) files. .TP .B BIBTOOL Search path for BibTool resource .RI ( .rsc ) files. .TP .B BIBTOOLRSC List of resource file names separated by colon. .SH FILES .TP .I ./.bibtoolrsc The default current directory .B BibTool resource file. .TP .I ~/.bibtoolrsc The default individual .B BibTool resource file. .TP .I /usr/local/lib/BibTool/*.rsc The BibTool resource files included in the original distribution. .SH SEE ALSO .IR bibtex (1), .IR latex (1), .IR tex (1) .br The .IR "BibTool Manual" . .SH BUGS Some arrays are allocated statically which may result in an overflow. .br Most memory is allocated but not returned to the OS: A garbage collection algorithm might be integrated in a future release. .br This man page is updated only occasionally, so it is very likely out of date. For complete, current documentation, refer to the .IR "BibTool Manual" which is distributed as LaTeX source file .RB ( bibtool.tex ) in the original .BR BibTool source distribution. .SH AUTHOR BibTool is designed and maintained by Gerd Neugebauer. .\".SH COPYRIGHT .\"Copyright (C) 1996\-2016 Gerd Neugebauer BibTool/doc/bibtool.tex0000644000175100017510000052022212646422520013757 0ustar genegene%%*** bibtool.tex ************************************************************* %% %% This file is part of BibTool. %% It is distributed under the Creative Commons Attribution-Share %% Alike 3.0 License. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %%----------------------------------------------------------------------------- %% Usage: latex bibtool %% bibtex bibtool %% latex bibtool %% makeindex -s bibtool.ist bibtool %% latex bibtool %%***************************************************************************** \documentclass[11pt,a4paper]{scrbook} \usepackage{bibtool-doc} \input{config.tex} \hypersetup{pdftitle={BibTool Manual}} \hypersetup{pdfauthor={Gerd Neugebauer}} \hypersetup{pdfsubject={Version \Version}} \makeindex \DeclareFontShape{OT1}{cmss}{m}{it}{<-> ssub * cmss/m/sl}{} \definecolor{keyword}{rgb}{0,.5,0} \definecolor{bibtex-bg}{rgb}{0.9607843137,0.9019607843,0.8235294118} \usepackage{listings} \lstdefinelanguage{BibTeX}{sensitive=false, basicstyle=\footnotesize\ttfamily, keywordstyle=\bfseries\color{keyword}, keywords={@string,@article,@book,@misc,@proceedings,@manual,@modify,@alias,@include}, backgroundcolor=\color{bibtex-bg}, frame=single, framerule=0pt} \lstdefinelanguage{BibTool}{sensitive=false, basicstyle=\scriptsize\ttfamily, keywordstyle=\bfseries\color{keyword}, backgroundcolor=\color{rsc-bg}, frame=single, framerule=0pt} \makeatletter%>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \newcommand\opt[1]{\texttt{-{}#1}\index{#1@{\tt-{}#1}}} \definecolor{sh-bg}{rgb}{.9,.9,.9} \definecolor{sh-border}{rgb}{.4,.4,.4} \newcommand\sh{\smallskip\par\hspace*{2em}\@ifnextchar[{\sh@}{\sh@@}} \def\sh@[#1]#2{% \fcolorbox{sh-border}{sh-bg}{\hspace*{1em}\begin{minipage}{.85\textwidth} \texttt{bibtool -{}#1 }\textit{#2}\index{#1@{\tt-{}#1}} \end{minipage}}\smallskip\par\noindent\ignorespaces} \newcommand\sh@@[1]{% \fcolorbox{sh-border}{sh-bg}{\hspace*{1em}\begin{minipage}{.85\textwidth} \texttt{bibtool }\textit{#1} \end{minipage}}\smallskip\par\noindent\ignorespaces} \makeatother%<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \newcommand\rsc[1]{\textsf{#1}\index{#1@\textsf{#1}}} \newcommand\rscEqBraces[2]{\rsc{#1} = \(\{\)#2\(\}\)} \newcommand\rscBraces[2]{\rsc{#1} \(\{\)#2\(\}\)} \newcommand\rscIt[1]{\textsf{\textit{#1}}} \newcommand\env[1]{\texttt{#1}\index{#1@{\tt #1}}} \definecolor{rsc-bg}{rgb}{.9,1,.9} \definecolor{rsc-border}{rgb}{.4,.6,.4} \newbox\rscbox \newenvironment{Resources}% {\setbox\rscbox=\hbox\bgroup\hspace*{.06\textwidth}\begin{minipage}{.88\textwidth}\sf\obeylines\obeyspaces }{\end{minipage}\egroup\vspace{1.5ex}% \fcolorbox{rsc-border}{rsc-bg}{\usebox\rscbox}% \medskip\par } \newcommand\code[1]{\texttt{#1}} \newcommand\file[1]{\textsf{#1}} \newcommand\off{\textsf{off}} \newcommand\on{\textsf{on}} \newcommand\bs{\texttt{\symbol{"5C}}\ignorespaces} \newcommand\BS{\(\backslash\)} \newcommand\Hat{\^{}} \newfont\cminch{cminch} \ifx\chaptername\relax\else \renewcommand\chaptername{\cminch} \renewcommand\appendixname{\cminch} \fi \newcommand\rfill[1]{\leaders\hrule height #1\hfill} \newenvironment{Summary}{\subsection*{Summary} \begin{center}\small \begin{tabular}{p{.08\textwidth}p{.35\textwidth}p{.48\textwidth}} \toprule \textit{\scriptsize Option}& \textit{\scriptsize Resource command}& \textit{\scriptsize Description}\\ \midrule }{\bottomrule\end{tabular}\end{center}} \newcommand\Desc[3]{\textit{#1}&\textit{#2}\\\hline} \newenvironment{Example}{\smallskip\par\textit{Example}\par}{\smallskip\par} \newenvironment{Disclaimer}{\begin{center}\sf\tiny --- }{ ---\end{center}} \newcommand\LINK[2]{\texttt{#2}} \newcommand\Link[2]{\href{#1}{\texttt{#2}}} \newcommand\email[1]{\href{mailto:#1}{\texttt{#1}}} \newcommand\FTP[2]{\texttt{#1}} \newcommand\ASCII{\textsc{ascii}} \begin{document} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \title{\BibTool{} Manual} \author{\(\cal G\)\hspace{-.1em}erd \(\cal N\)\hspace{-.2em}eugebauer} \maketitle \begin{Abstract} \BibTeX\ provides an easy to use means to integrate citations and bibliographies into \LaTeX\ documents. But the user is left alone with the management of the \BibTeX\ files. The program \BibTool\ is intended to fill this gap. \BibTool\ allows the manipulation of \BibTeX\ files which goes beyond the possibilities---and intentions---of \BibTeX. The possibilities of \BibTool\ include sorting and merging of \BibTeX\ data bases, generation of uniform reference keys, and selecting of references used in a publication. \end{Abstract} %\begin{Disclaimer} % This documentation is still in a rudimentary form and needs additional % efforts. %\end{Disclaimer} %------------------------------------------------------------------------------ \newpage \begingroup\setlength\parskip{1ex}\setlength\parindent{0pt} This file is part of \BibTool{} Version \Version \medskip\par Copyright \copyright{} \Year{} Gerd Neugebauer \medskip\par \BibTool{} is free software; you can redistribute it and/or modify it under the terms of the \LINK{GPL.html}{GNU General Public License} as published by the Free Software Foundation; either version 1, or (at your option) any later version. \BibTool{} 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 \LINK{GPL.html}{GNU General Public License} for more details. You should have received a copy of the \LINK{GPL.html}{GNU General Public License} along with this documentation; see the file \LINK{GPL.html}{COPYING}. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. \vfill\par Gerd Neugebauer\\ Im Lerchelsb\"ohl 5\\ 64521 Gro\ss-Gerau (Germany)\par\noindent Net: \Link{http://www.gerd-neugebauer.de/}{http://www.gerd-neugebauer.de/} \par\noindent E-Mail: \email{gene@gerd-neugebauer.de} \endgroup %------------------------------------------------------------------------------ \tableofcontents %------------------------------------------------------------------------------ \chapter{Introduction} The user's manual is divided into two parts. In this first part the big picture on \BibTool{} is shown. The next chapter after this one is then devoted to the nitty gritty details. \section{Related Programs} \BibTeX{} \cite{lamport:latex,patashnik:bibtexing,patashnik:designing} is a system for integrating bibliographic information into \LaTeX{} \cite{lamport:latex} documents. \BibTeX{} is designed to serve exactly this purpose. It has shown that various tasks in relation with managing bibliographic databases are not covered by \BibTeX. Usual activities on bibliographic databases include \begin{itemize} \item inserting new entries \item editing \item using citations in documents \item sorting and merging of bibliographic data bases \item extraction of bibliographic data bases \end{itemize} % Since only the integration in documents is covered by \BibTeX{} several utilities emerged to fill the gaps. We will sketch some of them shortly. % \begin{description} \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/distribs/}{\BibTeX}] is a program by Oren Patashnik to select publications used in a \LaTeX{} document and format them for inclusion into this document. This program should be part of each \TeX{} installation. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibclean/}{bibclean}] is a program by Nelson H.F.~Beebe to pretty-print \BibTeX{} files. It also can act as syntax checker. The C sources can be compiled on several systems. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/biblook/}{bibindex/biblook}] is a pair of programs by Nelson H.F.~Beebe to generate an index for a \BibTeX{} file and use it to perform a fast look-up of certain entries. The programs so far run only under UNIX. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibsort/}{bibsort}] is a UNIX shell script by Nelson H.F.~Beebe to sort a \BibTeX{} file. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibextract/}{bibextract}] is a UNIX shell script by Nelson H.F.~Beebe to extract entries from a \BibTeX{} file which are used in a \LaTeX{} document. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/lookbibtex/}{lookbibtex/bibdestringify}] are Perl scripts by John Heidemann to extract entries from a \BibTeX{} file which are used in a \LaTeX{} document and to remove strings from a \BibTeX{} file. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibtools/}{bibtools}] is a collection of UNIX shell scripts by David Kotz to add and extract entries to bibliographic databases. Several small programs are provided to perform special tasks. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibview/}{bibview}] is a Perl script by Dana Jacobsen to extract entries from a \BibTeX{} file which are used in a \LaTeX{} document. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibcard/}{BibCard}] is a program by William C.~Ogden running under X11/xview which provides a means to edit bibliographic databases. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/hyperbibtex/}{hyperbibtex}] Something similar for Macintosh computers. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/xbibtex/}{xbibtex/bibprocess/bibsearch}] are programs by Nicholas J. Kelly and Christian H. Bischof running under X11 which provides a means to edit bibliographic databases, add fields to a \BibTeX{} file and extract certain entries from a \BibTeX{} file. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/bibview/}{bibview}] is an X11 program by Holger Martin, Peter Urban, and Armin Liebl to search in and manipulate \BibTeX{} files. It is similar to BibCard and hyperbibtex. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/tkbibtex/}{tkbibtex}] is a \BibTeX{} file browser with support for editing, searching sorting and merging. Written by Peter Corke in Tcl/Tk it runs under Unix and Windows. \item [\href{http://www.ctan.org/tex-archive/support/bibdb/}{bibdb}] Editor for \BibTeX{} files that runs under Dos and Windows. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/qbibman/}{qbibman}] is a graphical user interface by Ralf G\"{o}rtz utilizing \BibTool{} as underlying library. It is written in C++ and uses Qt. \item [\href{http://barracuda.linuxbox.com/}{Barracuda}] an X11 Editor for \BibTeX{} files, written in C++ and Qt. \item [\BibTeX-Mode] is an extension of the editor GNU-Emacs to provide means to edit \BibTeX{} files. Several useful operations are provided. There is also a \BibTeX-Mode for the Emacs-like JED-Editor. \item [\href{http://www.ctan.org/tex-archive/biblio/bibtex/utils/btOOL/}{btOOL}] is a Perl library to access \BibTeX{} files. It is implemented in Perl and C and has been written by Greg Ward. \end{description} This is a selection of some programs I have heard of. I have tested some of them and I have skipped through the documentation of others. Thus the description may be too short or incomplete. Some additional information can be found in \cite[Chapter~13]{goosens.mittelbach.ea:companion}. Most of those utilities are tailored towards a particular operating system and thus they are not available on other platforms. Most of these program are made to perform a single task. Often they can not be configured to suit a personal taste of a user. Still there are some points not covered by the utilities mentioned above. \BibTool{} tries to provide the missing features and integrate others into a single tool. %------------------------------------------------------------------------------ \section{Using \BibTool{}---Some Instructive Examples} \BibTool\ has been developed on UN*X and UN*X-like machines. This has influenced many of the design decisions. Version 1 was controlled using numerous command line options. This way of controlling has been supplemented in version 2 by the concept of a resource file. This resource file allows the modification of the various internal parameters determining the behavior of \BibTool. When \BibTool\ has been compiled correctly there should be an executable file named \texttt{bibtool}\footnote{Maybe with an additional extension.}. We will assume that you are running \BibTool\ from a command line interpreter. There you can simply issue the command \sh{} Now \BibTool{} will start reading from the standard input lines obeying the rules of a \BibTeX{} file.\footnote{We assume that no resource file can be found. Resource files will be described later.} The entries read are pretty-printed on the standard output. It is obvious that this behavior is not very useful in itself. The origin of this kind of interface lies in the concepts of UN*X where many commands can act as filters. Usually we do not intend to use \BibTool{} in this way. Thus we need a way to specify an input file. This is simply done by adding the file name as argument after the command name like in \sh{file.bib} The result of this command can at once be seen on the screen. The contents of the file \texttt{file.bib} is pretty printed. Now that we have seen the simplest case of the application of \BibTool{} we will see the case of a useful application of \BibTool. This application is the sorting and merging of \BibTeX{} databases. %------------------------------------------------------------------------------ \subsection{Sorting and Merging}\label{sample.sort} \BibTeX{} files can be sorted by specifying the command line option \opt{s}. The given files are sorted according to the reference key. Several files can be given at once in which case \BibTool{} will sort and merge those files. \sh[s]{file1.bib file2.bib} With the command line option the files are sorted in reverse \ASCII{} order. \sh[S]{file1.bib file2.bib} If you want to sort the \BibTeX{} files according to the authors then the following invocation should do the trick:\index{N@\%N} \sh[s]{--sort.format="\%N(author)" file1.bib file2.bib} This means that the sorting order is determined by the (normalized) author field. Note that single quotes encapsulating the \rsc{sort.format} are necessary to prevent the command line interpreter to gobble the special characters. %------------------------------------------------------------------------------ \subsection{Key Generation} Once you have a reference and you insert it into a \BibTeX{} file you have to assign a reference key to it. The problem is to find a key which is unique and meaningful, i.e.\ easy to remember. The easiest way to remember a key is to use an algorithm to create it and remember the algorithm---which is the same for all keys. One algorithm which comes to mind is to use the author and (an initial part) of the title. Alternatively we can use the author and the year. But the problem is with industrious authors writing more than one publication per year. The necessary disambiguation of such references is not very intuitive. However, \BibTool{} has the capability to describe desired keys. Thus, the alternatives described above can be realized. For this section we want to use the following \BibTeX{} entry as our example:\footnote{Shamelessly stolen from the \BibTeX{} \file{xamples.bib} file.} Suppose it is contained in a file named \file{sample.bib}. \label{sample1}% \begin{lstlisting}[language=BibTeX] @ARTICLE{article-full, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, pages = "73+", month = jul, note = "This is a full ARTICLE entry", } \end{lstlisting} First, we want to see how we can make keys consisting of author and title. This is one of my favorite algorithms thus it is rather easy to use it. You simply have to run the following command: \sh[k]{\texttt{sample.bib -o sample1.bib}} After the command has completed it's work the following entry can be found in the output file \file{sample1.bib}: \begin{lstlisting}[language=BibTeX] @Article{ aamport:gnats, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, pages = "73+", month = jul, note = "This is a full ARTICLE entry" } \end{lstlisting} You see that the reference key has been changed. It now consists of the last name and the first relevant word of the title, separated by a colon. Sometimes it might be desirable to incorporate the initial names as well. This can be achieved by the command \sh[K]{\texttt{sample.bib -o sample1.bib}} The resulting reference key is \texttt{aamport.la:gnats}. The initials are appended after the first name. Thus the usual lexicographic order on the keys will (hopefully) bring together the publications of the same first author. Another alternative is to use the author and the year. This can be achieved with the following command:\footnote{Note that some command line interpreters (like the UN*X shells) require the format string to be quoted (enclosed in single quotes).}\index{n@\%n} \sh[f]{\texttt{\%n(author):\%2d(year) sample.bib -o sample1.bib}} The resulting key is \texttt{Aamport:86}. Note that the last example works as desired for our sample file. But for a real application of this technique a deep understanding of the key generation mechanism as described in section~\ref{sec:key.gen} is necessary. %------------------------------------------------------------------------------ \subsection{Normalization}\label{sample.norm} \BibTool{} can be used to normalize the appearance of \BibTeX{} databases. As an example we can consider the different forms of delimiters for fields. \BibTeX{} allows the use of of braces or double quotes. Now it can be desirable to use one style only. For this purpose the rewriting facility of \BibTool{} can be applied. \sh{-{}- \texttt{ 'rewrite.rule=\symbol{"7B}"\symbol{"5E}\symbol{"5C}"% \symbol{"5C}([\symbol{"5E}\#]*\symbol{"5C})\symbol{"5C}"\$" "\symbol{"7B}\symbol{"5C}1\symbol{"7D}"\symbol{"7D}'} \texttt{-o} out.bib} Since this seems to be rather cryptic we will have a closer look at this example. First we have to mention that the outer quotes are there because the UN*X shell (csh, sh, bash,...) treats some characters special and we want to avoid this to happen to the rewrite rule given. A similar quoting mechanism might be required for all command line interpreters. The rewrite rule is applied to any field. The first string---called pattern---which is enclosed in double quotes is matched against the contents of the field. If a match is found then the matching sub-string is replaced by the replacement text in the second string. The pattern is a regular expression\index{regular expression} like the ones used in Emacs\index{Emacs}. The first character is the hat (\verb|^|). This character anchors the match at the beginning of the line. The last character is the dollar sign which anchors the end at the end of the field value. Thus only complete matches are considered. Since we want to find those fields whose values are enclosed in double quotes they are given after the hat and before the dollar. To avoid a misinterpretation as the end of the pattern they have to be quoted with the backslash (\verb|\|). Next we have the parentheses \verb|\(|\ldots\verb|\)|. They are instructions to memorize the matching sub-string in a register. Since it is the first instruction of this kind the register number~1 is used. Now we come to the point where we have to specify the contents of the string. For this purpose we use a character class---written as \verb|[|\ldots\verb|]|. Since the first character in this class specification is a hat this class consists of all characters but those given after the hat. Thus all characters but the hash sign (\verb|#|\index{\#}) are allowed. The star (\verb|*|\index{*}) after the character class indicates that an arbitrary number of characters of this class are allowed. We have used the complicated construction with a character class to avoid wrong results which would have resulted when this rewrite rule is applied to a concatenated field value like the following one: \begin{lstlisting}[language=BibTeX] author = "A. U. Thor" # " and " # "S. O. Meone" \end{lstlisting} Such fields are left unchanged by the rewrite rule given above. We could have used the point (\verb|.|) instead of the character class since the point matches any character. But this would have let to the syntactic wrong result: \begin{lstlisting}[language=BibTeX] author = {A. U. Thor" # " and " # "S. O. Meone} \end{lstlisting} But we have to complete the explanation of the rewrite rule. The remaining part is the replacement text. Here we just have to note that the sub-string \verb|\1| is not copied verbose but replaced with the contents of the first register. This register contains the contents of the field without the delimiting double quotes. Thus we have a solution to our initial problem which is conservative in the sense that it sometimes fails but never produces a wrong result. %------------------------------------------------------------------------------ \subsection{Extracting Entries for a Document}\label{sample:extract} \BibTool{} can be used to extract the references used in a document. For this purpose \BibTool{} analyzes the \verb|.aux| file and takes the information given there. This includes the names of the \BibTeX{} files. Thus no \BibTeX{} files have to be given in the command line. Instead the \verb|.aux| file has to specified---preceded by the option \opt{x}. \sh[x]{document.aux \texttt{-o} document.bib} The second option \opt{o} followed by a file name specifies the destination of the output. This means, instead of writing the result to the standard output stream the result is written into this file. %------------------------------------------------------------------------------ \subsection{Extracting Entries Matching a Regular Expression} \BibTool{} can be used to extract the references which fulfill certain criteria. Those criteria can be specified utilizing regular expressions.\footnote{Those features are only usable if the regular expression library has been enabled during the configuration of \BibTool{}---which is the default.} As a special case we can extract all entries containing a certain sub-string of the key: \sh[X]{tex all.bib \texttt{-o} some.bib} This instruction selects all entries containing the sub-string \texttt{tex} in the key. The second option \opt{o} followed by a file name specifies the destination of the output. Thus instead of writing the result to the standard output stream the result is written into this file. Next we want to look up all entries containing a sub-string in some of its fields. For this purpose we search for the string in all fields first:\footnote{Note that some command line interpreters (e.g the UN*X shells) might need additional quoting of the select instruction since it contains special characters.} \sh[-]{select\{"tex"\} all.bib \texttt{-o} some.bib} Note that the comparison is not done case sensitive; however this can be customized (see page~\pageref{sec:extract}). Finally we want to select only those entries containing the sub-string in anyone of certain fields. For this purpose we simply specify the names of those fields in the \textit{select} instruction: \sh[-]{select\{title booktitle \$key "tex"\} all.bib \texttt{-o} some.bib} This example extracts all entries containing the sub-string \texttt{tex} in the title field, the booktitle field, or the reference key. After we have come so far we can say that the first example in this section is in fact a short version of the following command: \sh[-]{select\{\$key "tex"\} all.bib \texttt{-o} some.bib} As a simple case of extraction we might want to extract all books from a bibliography. This can be done with the following command: \sh[-]{select\{@book\} all.bib \texttt{-o} some.bib} A similar method can also be applied for other entry types. \begin{description} \item[Note] Usually cross-referenced entries are not selected automatically. This can result in incomplete---and thus incorrect---\BibTeX\ files. To avoid this behavior use the following command: \sh[-]{select\{\@{}book\} \texttt{-c} all.bib \texttt{-o} some.bib} \end{description} %------------------------------------------------------------------------------ \subsection{Translating ISO 8859-1 Characters} Sometimes you need to translate some special characters into \BibTeX\ sequences. Suppose you have edited a \BibTeX\ file and by mistake used those nice characters that are incompatible with standard \ASCII{} as used in \BibTeX. You can use \BibTool\ to do the trick: \sh[r]{iso2tex \texttt{-i} iso.bib \texttt{-o} ascii.bib} %------------------------------------------------------------------------------ \subsection{Correctly Sorting Cross-referenced Entries} \BibTeX\ has a restriction that a cross-referenced entry has to come after the referencing entry. This can be achieved by putting all entries containing a field ``crossref'' before those containing none. As second sorting criterion we want to use the reference key. This can be achieved with a resource file containing the following instructions\index{l@\%l} \begin{Resources} \rsc{sort.format} = \{\{\%1.\#s(crossref)a\#z\}\$key\} \rsc{sort.reverse} = off \rsc{sort} = on \end{Resources} The magic is contained in the first instruction. Thus we will examine it in detail: \begin{description} \item [\texttt{\%1.\#s(crossref)}]\index{l@\%l}\ \\ This formatting instruction does not produce any output but simply acts as condition to determine whether or not to include the following string. The condition counts the allowed characters (\texttt{\#s}) of the field \texttt{crossref} and compares this number with the given interval \([1,\infty]\) (\texttt{1.}). Thus it detects those entries containing a non empty crossref field. \item [\texttt{\%1.\#s(crossref)a}]\index{l@\%l}\ \\ If the condition holds then the string \texttt{a} is used as part of the sort key. \item [\texttt{\{\%1.\#s(crossref)a\#z\}}]\index{l@\%l}\ \\ If the first condition fails then the next alternative after the hash mark (\texttt{\#}) is considered. This is the string \texttt{z} which will always succeed and thus be included into the sort key. Thus this construction will produce \texttt{a} if a crossref field is present and not empty or \texttt{z} otherwise. \item [\texttt{\{\%1.\#s(crossref)a\#z\}\$key}]\index{l@\%l}\ \\ Finally the reference key (\texttt{\$key}) is appended to the characterizing initial letter. \end{description} The sorting according to ascending ASCII order will bring all the entries with crossref fields to the beginning. %------------------------------------------------------------------------------ \subsection{\BibTool\ for Bib\LaTeX} \BibTool contais the definitions to cope with \BibTeX\ files prepared for Bib\LaTeX. These definitions are contained in the library \file{biblatex.rsc}. It can be easily included on the command line: \sh[r]{biblatex \texttt{-i} in.bib \texttt{-o} out.bib} %------------------------------------------------------------------------------ \section{Interfacing \BibTool{} with Other Programming Languages} \BibTool{} can be used as a means for other programming languages to access \BibTeX{} data bases. In this course \BibTool{} reads the \BibTeX{} file and prints it in a normalized form which makes it easy for the host programming language to parse it and get the information about the entries and fields. In addition \BibTool{} can already preselect several entries or do other useful transformations before the host programming language even sees the contents. Thus it is fairly easy to write a CGI script (e.g.\ in Perl) which utilizes \BibTool{} to extract certain entries from a \BibTeX{} data base and presents the result on a HTML page. Currently the distribution of \BibTool{} contains frames of programs in Perl and Tcl which can be used as a basis for further developments. I am working towards making \BibTool{} a linkable library of C code. As one step into this direction the exported functions and header information has been documented. This documentation is contained in the distribution. A tight integration of BibTool into another programming language is possible. As an experiment into this direction I have chosen Tcl as the target language. The result is BibTcl which is contained in the distribution of \BibTool. %------------------------------------------------------------------------------ \section{Getting \BibTool, Hot News, and Bug Reports} Usually \BibTool{} can be found on the CTAN or one of its mirrors. Thus you can get \BibTool{} via HTTP or FTP or extract it from a DVD containing a dump of the CTAN. It can be found in the following location: \begin{list}{}{} \item \Link{http://mirrors.ctan.org/biblio/bibtex/utils/bibtool}% {http://mirrors.ctan.org/biblio/bibtex/utils/bibtool} \end{list} A signature for the source bundle is provided as well. My public key can be found on \Link{http://pgp.mit.edu/}{http://pgp.mit.edu/}. You should search for \texttt{gene@gerd-neugebauer.de}. \BibTool\ is hosted in a public repository at \Link{https://github.com}{github}\footnote{It used to be on Sarovar 'till December 2013.}. The repository contains the released sources as well as the development versions. The repository can be found at \begin{quote} \Link{https://github.com/ge-ne/bibtool}{https://github.com/ge-ne/bibtool} \end{quote} I have set up a WWW page for \BibTool. It contains a short description of the features and links to the documentation and the current downloadable version in source form. The URL is: \begin{quote} \Link{http://www.gerd-neugebauer.de/software/TeX/BibTool/}{http://www.gerd-neugebauer.de/software/TeX/BibTool/} \end{quote} In addition, this page contains a description of the current version of \BibTool{} and a list of changes in the last few releases. If you encounter problems installing or using \BibTool{} you can send me a bug report to my email address \texttt{gene@gerd-neugebauer.de}. Please include the following information into a bug report: \begin{itemize} \item The version of \BibTool{} you are using. \item Your hardware specification and operating system version. \item The C compiler you are using and its version. (Only for compilation and installation problems) \item The resource file you are using. Try to reduce it to the absolute minimum necessary for demonstrating the problem. \item A \emph{small} \BibTeX{} file showing the problem. \item The command line options of an invocation of \BibTool{} making the problem appear. \item A short justification why you think that the behavior is an error. \end{itemize} I have had the experience that compiling this information has helped me find my own problems in using software. Thus I could fix several problems before sending a bug report. On the other side I have unfortunately also had the experience that I have got complains about problems in my software. After several questions it turned out that the program had not been used properly. Oh, sure. There have been bugs and I suppose there are still some bugs in \BibTool. I am grateful for each hint which helps me eliminating these bugs. \section{Contributing to \BibTool} As you might have read \BibTool{} is free software in the sense of the Free Software Foundation. This means that you can use it as a whole or parts of it as long as you do not deny anyone to have the sources and use it freely. See the file \LINK{COPYING}{COPYING} for details. If you feel morally obliged to provide compensation for the use of this program I have the following suggestions. \begin{itemize} \item Proofread this documentation and report any errors you find as well as additional material to put in. \item Provide additional contributed pieces to \BibTool. For instance useful resource files which could be included into the library. \item Write a useful program and release it to the public without making profit, preferably under an Open Source license like the \LINK{GPL.html}{GNU General Public License} or the GNU artistic license. \end{itemize} %------------------------------------------------------------------------------ \appendix \chapter{Reference Manual} %------------------------------------------------------------------------------ This part of the documentation tries to describe all commands and options. Since the behavior of \BibTool{} can be adjusted at compile time not all features may be present in your executable. Thus watch out and complain to the \emph{installer} if something is missing. %------------------------------------------------------------------------------ \section{Beware of the Command Line} Be aware that command line interpreters have different ideas about what to do with a command line before passing the arguments to a program. Thus it might be necessary to carefully quote the arguments. Especially if the command contains spaces it is very likely that quoting is needed. For instance in UN*X shells it is in general a good strategy to enclose command line arguments in single quotes (\verb|'|) if they contain white-space or special characters like \texttt{\symbol{"5C}}, \texttt{\$}, \texttt{\&}, \verb|!|, or \verb|#|.´ Instead of excessively using command line arguments it is preferable and less error-prone to put the major configuration into a resource file and just include this resource file on the command line. Details on this are described in the next section. %------------------------------------------------------------------------------ \section{Command Line Usage and Resource Files} \BibTool{} can be controlled either by arguments given in the command line or by commands given in a file (or both). Those command files are called resource files. If \BibTool{} is installed correctly you should have the executable command \texttt{bibtool} (maybe with an additional extension). Depending on your computer and operating system you can start \BibTool{} in different ways. This can be done either by issuing a command in a command line interpreter (shell), by clicking an icon, or by selecting a menu item. In the following description we will concentrate on the use in a UN*X like shell. There you can type simply \sh{} Now \BibTool{} is waiting for your input. As you type \BibTool{} reads what you type. This input is interpreted as data conforming \BibTeX{} file rules. The result is printed when \BibTool{} is finished. You can terminate the reading phase with your End-Of-File character (e.g.\ Control-D on UN*X, or Control-Z on MS-D*S) This application in itself is rather uninteresting. Thus we come to the possibility to give arguments to \BibTool. The simplest argument is \opt{h} as in \sh[h]{} This command should print the version number and a short description of the command line arguments to the screen. The next application is the specification of resources. Resource files can be given in the command line after the flag \opt{r}. \sh[r]{resource\_file} In this way an arbitrary number of resource files can be given. Those resource files are read in turn and the commands contained are evaluated. If no resource file is given in the command line \BibTool{} tries to find one in standard places. First of all the environment variable \env{BIBTOOLRSC} is searched. If it is defined then the value is taken as a list of resource file names separated by colon (UNIX), semicolon (DOS), or comma (Amiga). All of them are tried in turn and loaded if they exist. If the environment variable is not set or no file could be loaded successfully then the default resource file (usually the file \texttt{.bibtoolrsc}) is tried to be read in the home directory (determined by the environment variable \env{HOME}) or the current directory. The resource files are searched similar to the searching mechanism for \BibTeX{} files (see section \ref{sec:search}). The extension \texttt{.rsc} is tried and a search path can be used. This search path is initialized from the environment variable \env{BIBTOOL}. Initially only the current directory is on the search path. The search path can also be set in a resource file (for following resource file reading). This can be achieved by setting the resource \rsc{resource.search.path}. \begin{Resources} \rsc{resource.search.path} = \emph{path} \end{Resources} When an explicit resource file is given in the command line the defaults are not used. To incorporate the default resource searching mechanism the command line option \opt{R} can be used: \sh[R]{} Now let us consider some examples. Suppose that the current directory contains a default resource file (named \file{.bibtoolrsc}) and an additional resource file \file{my\_rsc}. The following invocation of \BibTool{} uses only the resource file \textit{my\_rsc}: \sh{\texttt{-r} my\_rsc \texttt{-i} sample} If you want to initialize the resources from the default resource file before you can use the \opt{R} \emph{before} the inclusion of the resource file: \sh{\texttt{-R} \texttt{-r} my\_rsc \texttt{-i} sample} If you add the \opt{R} argument after the resource specification then the default resource is evaluated after your resource file. Thus settings are potentially overwritten: \sh{\texttt{-r} my\_rsc \texttt{-R} \texttt{-i} sample} Additionally note that resource files are evaluated at once whereas input files are read in one chunk at the end. Thus you can not specify one set of parameters to be used for one file and another set of parameters for the next file. This is impossible within one invocation of \BibTool\footnote{This might be changed in the next major revision (3.0).}. As a consequence of this behavior the last example is equivalent to the following invocations: \sh{\texttt{-r} my\_rsc \texttt{-i} sample \texttt{-R}}\vspace*{-4ex} \sh{\texttt{-i} sample \texttt{-r} my\_rsc \texttt{-R}} \medskip Now we have to describe the commands allowed in a resource file. The general form of a resource command is of the form \begin{Resources} \rscIt{name} = $\{$\textit{value}$\}$ \end{Resources} \rscIt{name} is the resource name which conforms the rules of \BibTeX{} reference keys. Thus \rscIt{name} can be composed of all characters but white-space characters and\index{\#}\index{\%}\index{=}\index{,}\index{\"@\"{}}% \index{'}\index{(}\index{)}\index{\{@$\{$}\index{\}@$\}$} \begin{verbatim} " # % ' ( ) , = { } \end{verbatim} Resource names are currently composed of letters and the period. The next component is an optional equality sign (\texttt{=}). The equality sign is recommended as it helps detecting syntax problems. White-space characters surrounding the equality sign or separating resource name and resource value are ignored. The resource value can be of the following kind: \begin{itemize} \item A number composed of digits only. \item A string conforming the rules of resource names, i.e.\ made up of all but the forbidden characters described above. \item A string containing arbitrary characters delimited by double quotes (") not containing double quotes. Parentheses and curly brackets have to come in matching pairs. \item A string containing arbitrary characters delimited by curly brackets (\{\}). Parentheses and curly brackets have to come in matching pairs. \end{itemize} You can think of resource names as variables or functions in a programming language. Resource commands simply set the variables to the given value, add the value to the old value, or initiate a action. There are different types of resources \begin{itemize} \item Boolean resources can take only the values \rsc{on} and \rsc{off}. The values \rsc{on}, \rsc{t}, \rsc{true}, 1, and \rsc{yes} are interpreted as the same. For those values the case of the letters is ignored. Thus \rsc{true} and \rsc{TrUe} are the same. Every other value else is interpreted as \rsc{off}. \item Numeric resources can take numeric values only. \item String resources can take arbitrary strings. \end{itemize} Usually white-space characters are ignored. There is one exception. The characters \texttt{\%} and \texttt{\#} act as comment start characters if given between resource commands. All characters to the end of the line are ignored afterwards. Now we come the description of the first resource available. To read in additional resource files the resource file may contain the resource \begin{Resources} \rscBraces{resource}{additional/resource/file} \end{Resources} Thus the resource given above has the same functionality as the command line option \opt{r} described above. Path names should be specified in the normal manner for your operating system. One resource command useful for debugging is the \rsc{print} resource. The resource value is immediately written to the error stream. The output is terminated by a newline character. Certain translations are performed during the reading of a resource which can be observed when printing. Each sequence of white-space characters is translated into a single space. To end this subsection we give an example of the \rsc{print} resource. In this sample we also see the possibility to omit the equality sign and use quotes as delimiters. \begin{Resources} \rsc{print} "This is a stupid message." \end{Resources} Finally we can note that the commands given in a resource file can also be specified on the command line. This can be achieved with the command line option \opt{-} The next command line argument is taken as a resource command. \sh[-]{resource\_command} This can be used to issue resource commands which do not have a command line counterpart. One example we have already seen. The \rsc{print} instruction can be used from the command line with the following \sh[-]{print\{hello\_world\}} \medskip \begin{Summary} \Desc{\opt{h}}{}{Show a list of command line options.} \Desc{\opt{R}}{}{Immediately evaluate the instructions from the default file.} \Desc{}{\rsc{print} \{message\}}{Write out the text \textit{message}.} \Desc{\opt{r} file}{\rsc{resource} = file}{Immediately evaluate the instructions from the resource file \textit{file}.} \Desc{}{\rsc{resource.search.path}}{List of directories to search for resource files.} \Desc{\opt{-} rsc}{rsc}{Evaluate the resource instruction \textit{rsc}.} \end{Summary} %------------------------------------------------------------------------------ \section{Input File Specification and Search Path}\label{sec:search} An arbitrary number of input files can be specified. Input files can be specified in two ways. The command line option \opt{i} is immediately followed by a file name. Since no restriction on the file name is applied this can also be used to specify files starting with a dash. \sh[i]{input\_file} The resource name \rsc{input} can be used to specify additional input files. \begin{Resources} \rscBraces{input}{input\_file} \end{Resources} Input files are processed in the order they are given. If no input file is specified the standard input is used to read from. Depending on the special configuration of \BibTool{} there are two ways of searching for \BibTeX{} files. The native mode of \BibTool{} uses a list of directories and a list of extensions to find a file. Alternatively the kpathsea library can be used which provides additional features like the recursive searching in sub-directories. First we look at the native \BibTool{} searching mechanism. The files are searched in the following way. If the file is can't be opened as given the extension \texttt{.bib} is appended and another read is tried. In addition directories can be given which are searched for input files. The search path can be given in two different ways. First, the resource name \rsc{bibtex.search.path} can be set to contain a search path specification. \begin{Resources} \rscEqBraces{bibtex.search.path}{directory1:directory2:directory3} \end{Resources} The elements of the search path are separated by colons. Thus colons are not allowed as parts of directories. Another source of the search path is the environment variable \env{BIBINPUTS}. This environment variable is usually used by \BibTeX{} to specify the search path. The syntax of the specification is the same as for the resource \rsc{bibtex.search.path}. To check the appropriate way to set your environment variable consult the documentation of your shell, since this is highly dependent on it. To allow adaption to operating systems other than UN*X the following resources can be used. The name of the environment \rsc{bibtex.env.name} overwrites the name of the environment variable which defaults to \env{BIBINPUTS}. \begin{Resources} \rscEqBraces{bibtex.env.name}{ENVIRONMENT\_VARIABLE} \end{Resources} The first character of the resource \rsc{env.separator} is used as separator of directories in the resource \rsc{bibtex.search.path} and the environment variable given as \rsc{bibtex.env.name}. \begin{Resources} \rscEqBraces{env.separator}{:} \end{Resources} The default character separating directories in a file name is the slash (\verb|/|). The first character of the resource \rsc{dir.file.separator} can be used to change this value. \begin{Resources} \rscEqBraces{dir.file.separator}{\BS} \end{Resources} \textbf{Note} that the defaults for \rsc{env.separator} and \rsc{dir.file.separator} are set at compile time to a value suitable for the operating system. Usually you don't have to change them at all. For instance for MSD*S machines the \rsc{env.separator} is usually set to \verb|;| and the \rsc{dir.file.separator} is usually set to \verb|\|. If the kpathsea library is used for searching \BibTeX{} files then some of the resources described above have no effect. They are replaced by their kpathsea counterparts. Most probably you are using the kpathsea library already in other \TeX{} related programs. Thus I just have to direct you to the documentation distributed with the kpathsea library for details. \begin{Summary} \Desc{}{\rsc{bibtex.env.name}=\{var\}}{Use the environment variable \textit{env} to add more directories to the search path for \BibTeX{} (input) files.} \Desc{}{\rsc{bibtex.search.path}=\{path\}}{Use the list of directories \textit{path} to find \BibTeX{} (input) files.} \Desc{}{\rsc{dir.file.separator}=\{c\}}{Use the character \textit{c} to separate the directory from the file.} \Desc{}{\rsc{env.separator}=\{c\}}{Use the character \textit{c} to separate directories in a path.} \Desc{\opt{i} file}{\rsc{input}\{file\}}{Add the \BibTeX{} file \textit{file} to the list of input files.} \end{Summary} %------------------------------------------------------------------------------ \section{Output File Specification and Status Reporting} By default, the processed \BibTeX{} entries are written to the standard output. This output can be redirected to a file using the command line option \opt{o} as in \sh[o]{output\_file} The resource name \rsc{output.file} can also be used for this purpose. \begin{Resources} \rscEqBraces{output.file}{output\_file} \end{Resources} No provisions are made to check if the output file is the same as a input file. A second output stream is used to display error messages and status reports. The standard error stream is used for this purpose. The messages can roughly be divided in three categories: error messages, warnings, and status reports. Error messages indicate severe problems. They can not be suppressed. Warnings indicate possible problems which could (possibly) have been corrected. They are displayed by default but can be suppressed. Status reports are messages during the processing which indicate actions currently performed. They are suppressed by default but can be enabled. Warning messages can be suppressed using the command line option \opt{q}. This option toggles the Boolean quiet value. \sh[q]{} The same effect can be obtained by assigning the value \textsf{on} or \textsf{off} to the resource \rsc{quiet}: \begin{Resources} \rsc{quiet} = on \end{Resources} Status reports are useful to see the operations performed. They can be enabled using the command line option \opt{v}. This option toggles the Boolean verbose value. \sh[v]{} The same can also be achieved with the Boolean resource \rsc{verbose}: \begin{Resources} \rsc{verbose} = on \end{Resources} Another output stream can be used to select the string definitions. This is described in section~\ref{sec:macros} on macros. %\iffalse %For completeness we can also mention that the internal symbol table can be %printed using the command line option \opt{\$} or the boolean resource %\rsc{dump.symbols}. This is mainly meant for debugging purposes. \emph{Please % send me a bug report and the diffs to fix it :-)} %\fi \begin{Summary} \Desc{\opt{o} file}{\rsc{output.file} \{file\}}{Direct output to the file \textit{file}.} \Desc{\opt{q}}{\rsc{quiet}=on}{Suppress warnings. Errors can not be suppressed.} \Desc{\opt{v}}{\rsc{verbose}=on}{Enable informative messages on the activities of \BibTool.} \end{Summary} %------------------------------------------------------------------------------ \section{Parsing and Pretty Printing}\label{sec:parse.pretty} The first and simplest task we have to provide on \BibTeX{} files is the parsing and pretty printing. This is not superfluous since \BibTeX{} is rather pedantic about the accepted syntax. Thus I decided to try to be generous and correct as many errors as I can. Each input file is parsed and stored in an internal representation. \BibTeX{} simply ignores any characters between entries. \BibTool{} stores the comments and attaches them to the entry immediately following them. Normally anything between entries is simply discarded and a warning printed. The Boolean resource \rsc{pass.comments} can be used to change this behavior. \begin{Resources} \rsc{pass.comments} = on \end{Resources} If this resource is on then the characters between entries are directly passed to the output file. This transfer starts with the first non-space character after the end of an entry. The standard \BibTeX{} styles support a limited number of entry types. Those are predefined in \BibTool. Additional entry types can be defined using the resource \rsc{new.entry.type} as in \begin{Resources} \rscBraces{new.entry.type}{Anthology} \end{Resources} This option can also be used to redefine the appearance of entry types which are already defined. Suppose we have defined \emph{Anthology} as above. Afterwards we can redefine this entry type to be printed in upper case with the following option: \begin{Resources} \rscBraces{new.entry.type}{ANTHOLOGY} \end{Resources} Each undefined entry type leads to an error message. When a database is printed the different kinds of entries are printed together. For instance all normal entries are printed en block. The order of the entry types is determined by the resource \rsc{print.entry.types}. The value of this resource is a string where each character represents an entry type to be printed. If a letter is missing then this part of the database is omitted. The following letters are recognized---uppercase letters are folded to their lowercase counterparts if they are not mentioned explicitly: \begin{description} \item [a] The aliases of the database. \item [c] The comments of the database which are not attached to an entry. \item [i] The includes of the database. \item [m] The modifies of the database. \item [n] The normal entries of the database. \item [p] The preambles of the database. \item [\$] The strings (macros) of the database. \item [S] The strings (macros) of the database which are used in the other entries. \item [s] The strings (macros) of the database where the resource \rsc{print.all.strings} determines whether all strings are printed or the used ones only. \end{description} The following invocation prints the preambles and the normal entries only. This can be desirable if the macros are printed into a separate file. \begin{Resources} \rscBraces{print.entry.types}{pn} \end{Resources} The internal representation is printed in a format which can be adjusted by certain options. Those options are available through resource files or by specifying resources on the command line. \begin{description} \item [\rsc{print.line.length}] This numeric resource specifies the desired width of the lines. lines which turn out to be longer are tried to split at spaces and continued in the next line. The value defaults to 77. \item [\rsc{print.indent}] This numeric resource specifies indentation of normal items, i.e.\ items in entries which are not strings or comments. The value defaults to 2. \item [\rsc{print.align}] This numeric resource specifies the column at which the '=' in non-comment and non-string entries are aligned. This value defaults to 18. \item [\rsc{print.align.key}] This numeric resource specifies the column at which the '=' in non-comment and non-string entries are aligned. This value defaults to 18. \item [\rsc{print.align.string}] This numeric resource specifies the column at which the '=' in string entries are aligned. This value defaults to 18. \item [\rsc{print.align.preamble}] This numeric resource specifies the column at which preamble entries are aligned. This value defaults to 11. \item [\rsc{print.align.comment}] This numeric resource specifies the column at which comment entries are aligned.\footnote{This is mainly obsolete now since comments do not have to follow any syntactic restriction.} This value defaults to 10. \item [\rsc{print.comma.at.end}] This Boolean resource determines whether the comma between fields should be printed at the end of the line. If it is \textsf{off} then the comma is printed just before the field name. In this case the alignment given by \rsc{print.align} determines the column of the comma. \item [\rsc{print.equal.right}] This Boolean resource specifies whether the = sign in normal entries is aligned right. If turned off then the = sign is flushed left to the field name. This value defaults to \textsf{on}. \item [\rsc{print.newline}] This numeric resource specifies the number of newlines between entries. This value defaults to 1. \item [\rsc{print.terminal.comma}] This Boolean resource specifies whether a comma should be printed after the last record of a normal entry. This contradicts the rules of \BibTeX\ but might be useful for other programs. This value defaults to \textsf{off}. \item [\rsc{print.use.tab}] This Boolean resource specifies if the \texttt{TAB} character should be used for indenting. This use is said to cause portability problems. Thus it can be disabled. If disabled then the appropriate number of spaces are inserted instead. This value defaults to \textsf{on}. \item [\rsc{print.wide.equal}] This Boolean resource determines whether the equality sign should be forced to be surrounded by spaces. Usually this resource is \off{} which means that no spaces are required around the equality sign and they can be omitted if the alignment forces it. \item [\rsc{suppress.initial.newline}] This Boolean resource suppresses the initial newline before normal records since this might be distracting under certain circumstances. \end{description} The resource values described above are illustrated by the following examples. First we look at a string entry. \bigskip \ifHTML {\small \begin{verbatim} | | | print.align.string print.line.length | \end{verbatim} } \else \noindent \vbox{ \begin{minipage}{\textwidth} \begingroup% \settowidth{\unitlength}{\texttt{\small m}}% \begin{picture}(0,2)(0,-3) \put(18,0){\line(0,1){5.5}} \put(77,0){\line(0,1){5.5}} \put(77,0){\makebox(0,0)[r]{\rsc{print.line.length}}} \put(18,0){\makebox(0,0)[l]{\rsc{print.align.string}}} \end{picture} \endgroup \vspace{1ex}\end{minipage}} \fi Next we look at an unpublished entry. It has a rather long list of authors and a long title. It shows how the lines are broken. \vspace{4.5ex} \ifHTML {\small \begin{verbatim} | print.align.key | @Unpublished{ unpublished-key, author = "First A. U. Thor and Seco N. D. Author and Third A. Uthor and others", title = "This is a rather long title of an unpublished entry which exceeds one line", note = "Some useless comment" } | | | | print.indent | print.align print.line.length | \end{verbatim} } \else \noindent \hbox{% \begin{minipage}{\textwidth} {\small \begin{verbatim} @Unpublished{ unpublished-key, author = "First A. U. Thor and Seco N. D. Author and Third A. Uthor and others", title = "This is a rather long title of an unpublished entry which exceeds one line", note = "Some useless comment" } \end{verbatim}% }% \settowidth{\unitlength}{\texttt{\small m}}% \begin{picture}(0,2)(0,-3) \put( 2,0){\line(0,1){14.5}} \put(18,15.5){\line(0,1){3.5}} \put(18,0){\line(0,1){14.5}} \put(77,0){\line(0,1){14.5}} \put(18,19){\makebox(0,0)[l]{\rsc{print.align.key}}} \put(77,0){\makebox(0,0)[r]{\rsc{print.line.length}}} \put(18,0){\makebox(0,0)[l]{\rsc{print.align}}} \put( 2,0){\makebox(0,0)[l]{\rsc{print.indent}}} \end{picture} \end{minipage}} \vspace{1ex} \fi The field names of an entry are usually printed in lower case. This can be changed with the resource \rsc{new.field.type}. The argument of this resource is an equation where left of the '=' sign is the name of a field and on the right side is it's print name. They should only contain allowed characters. \begin{Resources} \rsc{new.field.type} {\(\{\) author = AUTHOR \(\}\)} \end{Resources} This feature can be used to rewrite the field types. Thus it is completely legal to have a different replacement text than the original field: \begin{Resources} \rsc{new.field.type} {\(\{\) OPTauthor = Author \(\}\)} \end{Resources} String names are used case insensitive by \BibTeX. \BibTool{} normalizes string names before printing. By default string names are translated to lower case. Currently two other types are supported: translation to upper case and translation to capitalized case, i.e. the first letter upper case and the others in lower case. The translation is controlled by the resource \rsc{symbol.type}\label{symbol.type}. The value is one of the strings \verb|lower|, \verb|upper|, and \verb|cased|. The resource can be set as in \begin{Resources} \rsc{symbol.type} = upper \end{Resources} The macro names are passed through the same normalization apparatus as field types. Thus you can force a rewriting of macro names with the same method as described above. You should be careful when choosing macro names which are also used as field types. The reference key is usually translated to lower case letters unless a new key is generated (see section~\ref{sec:key.gen}). In this case the chosen format determines the case of the key. Sometimes it can be desirable to preserve the case of the key as given (even so \BibTeX{} does not mind). This can be achieved with the Boolean resource \rsc{preserve.key.case}. Usually it is turned off (because of backward compatibility and the memory used for this feature). You can turn it on as in \begin{Resources} \rsc{preserve.key.case} = on \end{Resources} If it is turned on then the keys as they are read are recorded and used when printing the entries. The internal comparisons are performed case insensitive. This is not influenced by the resource \rsc{preserve.key.case}. Especially this holds for sorting which does not recognize differences in case. \begin{Summary} \Desc{}{\rsc{new.entry.type}\{type\}}{Define a new entry type \textit{type}.} \Desc{}{\rsc{new.field.type}\{type\}}{Define a new field type \textit{type}.} \Desc{}{\rsc{pass.comments}=on}{Do not discard comments but attach them to the entry following them.} \Desc{}{\rsc{preserve.key.case}=on}{Do not translate keys to lower case when reading.} \Desc{}{\rsc{print.align.comment}=n}{Align comment entries at column \textit{n}.} \Desc{}{\rsc{print.align.key}=n}{Align the key of normal entries at column \textit{n}.} \Desc{}{\rsc{print.align.string}=n}{Align the \texttt{=} of string entries at column \textit{n}.} \Desc{}{\rsc{print.align}=n}{Align the \texttt{=} of normal entries at column \textit{n}.} \Desc{}{\rsc{print.comma.at.end}=on}{Put the separating comma at then end of the line instead of the beginning.} \Desc{}{\rsc{print.indent}=n}{Indent normal entries to column \textit{n}.} \Desc{}{\rsc{print.line.length}=n}{Break lines at column \textit{n}.} \Desc{}{\rsc{print.print.newline}=n}{Number of empty lines between entries.} \Desc{}{\rsc{print.use.tab}=on}{Use the \texttt{TAB} character to compress multiple spaces.} \Desc{}{\rsc{print.wide.equal}=off}{Force spaces around the equal sign.} \Desc{}{\rsc{suppress.initial.newline}=on}{Suppress the initial newline before normal records.} \Desc{}{\rsc{symbol.type}=type}{Translate symbols according to \textit{type}: upper, lower, or cased.} \end{Summary} %------------------------------------------------------------------------------ \section{Sorting}\label{sorting} The entries can be sorted according to a certain sort key. The sort key is by default the reference key. Sorting can enabled with the command line switches \opt{s} and \opt{S} as in \sh[s]{}\vspace{-4ex} \sh[S]{} The first variant sorts in ascending \ASCII{} order (including differentiation of upper and lower case). The second form sorts in descending \ASCII{} order. The same effect can be achieved with the Boolean resource values \rsc{sort} and \rsc{sort.reverse} respectively. \begin{Resources} \rscEqBraces{sort}{on} \rscEqBraces{sort.reverse}{on} \end{Resources} The resource \rsc{sort} determines whether or not the entries should be sorted. The resource \rsc{sort.reverse} determines whether the order is ascending (off) or descending (on) \ASCII{} order of the sort key. The sort key is initialized from the reference key if not given otherwise. Alternatively the sort key can be constructed according to a specification. This specification can be given in the same way as a specification for key generation. This is described in section \ref{sec:key.gen} in detail. The associated resource name is \rsc{sort.format}. Several formats are combined as alternatives. \begin{Resources} \rscEqBraces{sort.format}{\%N(author)}\index{N@\%N} \rscEqBraces{sort.format}{\%N(editor)} \end{Resources} Those two lines are equivalent with the single resource \begin{Resources} \rscEqBraces{sort.format}{\textit{\%N(author) \# \%N(editor)}}\index{N@\%N} \end{Resources} This means that the sort key is set to the (normalized) author names if an author is given. Otherwise it tries to use the normalized editor name. If everything fails the sort key is empty. Let us reconsider the unprocessed example on page \pageref{sample1}. Without any \rsc{sort.format} instructions this entry would sorted in under ``article-full''. With the \rsc{sort.format} given above it would be sorted in under ``Aamport.LA''. \textbf{Note} that in \ASCII{} order the case is important. The uppercase letters all come before the lowercase letters. \medskip Usually the keys are folded to lower case during the normalization. Thus the lower case variants are also used for comparison. The resource \rsc{preserve.key.case} can be used to print cased keys as they are encountered in the input file. This feature can be combined with the Boolean resource \rsc{sort.cased} to achieve sorting according to the unfolded reference key: \begin{Resources} \rscEqBraces{preserve.key.case}{on} \rscEqBraces{sort.cased}{on} \end{Resources} Beside the normal entries the macros (string entries) are sorted. This happens in per default. The resource \rsc{sort.macros} can be used to turn off this feature as in \begin{Resources} \rscEqBraces{sort.macros}{off} \end{Resources} An example of sorting can be seen in section~\ref{sample.sort} on page \pageref{sample.sort}. \begin{Summary} \Desc{\opt{S}}{}{Enable sorting of entries in reverse sorting order.} \Desc{\opt{s}}{\rsc{sort}}{Enable sorting of entries.} \Desc{}{\rsc{sort.cased}=on}{Use the cased form of the reference key for sorting.} \Desc{}{\rsc{sort.format}\{spec\}}{Add disjunctive branch \textit{spec} to the sort key specifier.} \Desc{}{\rsc{sort.macros}=off}{Turn off the sorting of string entries.} \Desc{}{\rsc{sort.reverse}=on}{Reverse the sorting order.} \end{Summary} %------------------------------------------------------------------------------ \section{Regular Expression Matching}\label{sec:regex} \BibTool{} makes use of the GNU regular expression library. Thus a short excursion into regular expressions is contained in this manual. Several examples of the application of regular expressions can be found also in other sections of this manual. A concise description of regular expressions is contained in the document \file{regex-0.12/regex.texi} contained in the \BibTool{} distribution. In any cases of doubt this documentation is preferable. The remainder of this section contains a short description of regular expressions. Note that the default regular expressions of the Emacs style are used. \begin{description} \item[Ordinary characters] match only to themselves or their upper or lower case counterpart. Any character not mentioned as special is an ordinary character. Among others letters and digits are ordinary characters. For instance the regular expression \emph{abc} matches the string \emph{abc}. \item[The period] (\verb|.|) matches any single character. For instance the regular expression \emph{a.c} matches the string \emph{abc} but it does not match the string \emph{abbc}. \item[The star] (\verb|*|) is used to denote any number of repetitions of the preceding regular expression. If no regular expression precedes the star then it is an ordinary character. For instance the regular expression \emph{ab*c} matches any string which starts with a followed by an arbitrary number of b and ended by a c. Thus it matches \emph{ac} and \emph{abbbc}. But it does not match the string \emph{abcc}. \item[The plus] (\verb|+|) is used to denote any number of repetitions of the preceding regular expression, but at least one. Thus it is the same as the star operator except that the empty string does not match. If no regular expression precedes the plus then it is an ordinary character. For instance the regular expression \emph{ab+c} matches any string which starts with a followed by one or more b and ended by a c. Thus it matches \emph{abbbc}. But it does not match the string \emph{ac}. \item[The question mark] (\verb|?|) is used to denote an optional regular expression. The preceding regular expression matches zero or one times. If no regular expression precedes the question mark then it is an ordinary character. For instance the regular expression \emph{ab?c} matches any string which starts with a followed by at most one b and ended by a c. Thus it matches \emph{abc}. But it does not match the string \emph{abbc}. \item[The bar] (\verb/\|/) separates two regular expressions. The combined regular expression matches a string if one of the alternative separated by the bar does. Note that the bar has to be preceded by a backslash. For instance the regular expression \emph{abc\(\backslash\mid\)def} matches the string \emph{abc} and the string \emph{def}. \item[Parentheses] (\verb|\(\)|) can be used to group regular expressions. A group is enclosed in parentheses. It matches a string if the enclosed regular expression does. Note that the parentheses have to be preceded by a backslash. For instance the regular expression \emph{\(a\backslash(b\backslash\mid\backslash d)c\)} matches the strings \emph{abc} and \emph{adc}. \item[The dollar] (\verb|$|) %$ matches the empty string at the end of the string. It can be used to anchor a regular expression at the end. If the dollar is not the end of the regular expression then it is an ordinary character. For instance the regular expression \emph{abc\$} matches the string \emph{aaaabc} but does not match the string \emph{abcdef}. \item[The hat] (\texttt{\Hat}) matches the empty string at the beginning of the string. It can be used to anchor a regular expression at the beginning. If the hat is not the beginning of the regular expression then it is an ordinary character. There is one additional context in which the hat has a special meaning. This context is the list operator described below. For instance the regular expression \emph{\Hat abc} matches the strings \emph{abcccc} but does not match the string \emph{aaaabc}. \item[The brackets] (\verb|[]|) are used to denote a list of characters. If the first character of the list is the hat (\texttt{\Hat}) then the list matches any character not contained in the list. Otherwise it matches any characters contained in the list. For instance the regular expression \emph{[abc]} matches the single letter strings \emph{a}, \emph{b}, and \emph{c}. It does not match \emph{d}. The regular expression \emph{[\Hat abc]} matches any single letter string not consisting of an a, b, or c. \item[The backslash] (\texttt{\BS}) is used for several purposes. Primarily it can be used to quote any special character. Thus if a special character is preceded by the backslash then it is treated as if it were an ordinary character. If the backslash is followed by a digit \(d\)\/ then this construct is the same as the \(d^{th}\) matching group. For instance the regular expression \emph{(an)\BS1as} matches the string \emph{ananas} since the first group matches \emph{an}. If the backslash is followed by the character \texttt{n} then this is equivalent to entering a newline. If the backslash is followed by the character \texttt{t} then this is equivalent to entering a single \texttt{TAB} character. \end{description} %------------------------------------------------------------------------------ \section{Selecting Items} \subsection{Extracting by \texttt{aux} Files} \BibTool{} includes a module to extract \BibTeX{} entries required for a document. This is accomplished by analyzing the \texttt{aux} file of the document. The \texttt{aux} file is usually produced by \LaTeX. It contains the information which \BibTeX{} files and which references are used in the document. Only those entries mentioned in the \texttt{aux} file are selected for printing. Since the \BibTeX{} files are already named in the \texttt{aux} file it is not necessary to specify an input file. To use an \texttt{aux} file the command line option \opt{x} can be given. This option is followed by the name of the \texttt{aux} file. \sh[x]{file.aux} Multiple files can be given this way. As always the same functionality can be requested with a resource. The resource \rsc{extract.file} can be used for this purpose. \begin{Resources} \rscBraces{extract.file}{\textit{file.aux}} \end{Resources} A small difference exists between the two variants. the command line option automatically sets the resource \rsc{print.all.strings} to \verb|off|. This has to be done in the resource file manually. Note that the extraction automatically respects the cross-references in the selected entries. Thus you will get a complete \BibTeX\ file---unless some references can not be resolved and an error is produced. One special feature of \BibTeX{} is supported. If the command \verb|\nocite{*}| is given in the \LaTeX{} file then all entries of the bibliography files are included in the bibliography. The same behavior is imitated by the extracting mechanism of \BibTool. An example of extracting can be seen in section~\ref{sample:extract} on page \pageref{sample:extract}. \subsection{Extracting with Sub-string Matching} The simplest way of specifying an entry---except by giving its key---is to give a string which has to be present in one of the fields or pseudo fields. The resource \rsc{select.by.string} can be used to store a selection rule which is applied at the appropriate time later on. If several rules are supplied then any entry matching one of the rules is selected. Thus different rules act as alternatives. This includes rules with regular expressions as described in section~\ref{sec:extract}. The simplest form of the resource \rsc{select.by.string} is to specify a single string to search for. This string has to be enclosed in double quotes. Since the argument of the resource has to be enclosed in braces we get the following funny syntax: \begin{Resources} \rscBraces{select.by.string}{"some string"} \end{Resources} This operation selects all entries containing \texttt{some string} in one of the normal fields. The search can be restricted to specific fields or extended to pseudo fields by specifying those fields before the search string. An arbitrary number of white-space separated fields can be given there. Thus the general syntax for this resource is as follows: \begin{Resources} \rscBraces{select.by.string}{\textit{field\(_1\) \(\ldots\) field\(_n\) "string"}} \end{Resources} To make this selection operation more flexible it is possible to determine whether or not the comparison against the value of a field is performed case sensitive. This can be done with the Boolean resource \rsc{select.case.sensitive}. Since the selection is performed after all resources have been read the value of this resource is only considered then. Thus it is not possible to mix case sensitive and non case sensitive selections as with regular expressions (see section~\ref{sec:extract}). During the matching of the search string against the value of a field \BibTool{} ignores certain characters. Thus it is possible to hide irrelevant details like braces or spaces. The characters to ignore are stored in the resource \rsc{select.by.string.ignored}. As a default the following resource command is performed implicitly: \begin{Resources} \rscBraces{select.by.string.ignored}{"\{\} []"} \end{Resources} As for the resource \rsc{select.case.sensitive} the evaluation of the resource \rsc{select.by.string.ignored} is performed just before the comparisons are carried out. Thus it is not possible to use several rules with different ignored sets of characters. In addition to the functionality described above the resource \rsc{select.by.non.string} can be used to select all entries for which the match against the given field fails. The general form is the same as for \rsc{select.by.string}: \begin{Resources} \rscBraces{select.by.non.string}{\textit{field\(_1\) \(\ldots\) field\(_n\) "string"}} \end{Resources} \begin{description} \item[Note] Cross-references are not considered unless \rsc{select.crossrefs} is set. \end{description} \subsection{Extracting with Regular Expressions}\label{sec:extract} Another selecting mechanism uses regular expressions to select items. This feature can be used in addition to the selection according to \texttt{aux} files. The regular expression syntax is identical to the one used in GNU Emacs. For a description see section \ref{sec:regex}. The resource \rsc{select} allows to specify which fields should be used to select entries. The general form is as follows: \begin{Resources} \rscBraces{select}{\textit{field\(_1\) \(\ldots\) field\(_n\) "regular\_expression"}} \end{Resources} If no field is specified then the regular expression is searched in each field. If no regular expression is specified then any value is accepted; i.e. the regular expression \texttt{"."} is used. Any number of selection rules can be given. An entry is selected if one of those rules selects it. The select rule selects an entry if this entry has a field named \emph{field} which has a sub-string matching \emph{regular\_expression}. The field can be missing in which case the regular expression is tried to match against any field in turn. The pseudo fields \verb|$key|, \verb|$type|, and \verb|@|\emph{type} can be used to access the key and the type of the entry. See page \pageref{pseudo:key} for details. The routines used there are the same as those used here. Analogously to the negation of the string matching the regular expression matching can be negated. The resource to perform this functionality is \rsc{select.non}. The general form is \begin{Resources} \rscBraces{select.non}{\textit{field\(_1\) \(\ldots\) field\(_n\) "regular\_expression"}} \end{Resources} The Boolean resource \rsc{select.case.sensitive} can be used to determine whether the selection is performed case sensitive or not: \begin{Resources} \rscEqBraces{select.case.sensitive}{off} \end{Resources} Note that the selection does not take place immediately. Instead all selection rules are collected and the selection is performed at an appropriate time later on. The different selection rules are treated as alternatives. Thus any entry which matches at least one of the rules is selected. Nevertheless the value of the resource \rsc{select.case.sensitive} is used which is in effect when the selection rule is issued. Thus it is possible to mix case sensitive rules with non-case sensitive rule. A regular expression can be specified in the command line using the option \opt{X} as in \sh[X]{regular\_expression} The fields compared against this regular expression are given in the string valued resource \rsc{select.fields}. Initially this resource has the value \verb|$key|. In general the value is a list of fields and pseudo fields to be considered. The elements of the list are separated by spaces. If the list is empty then all fields and the key are considered for comparison. %$ Thus the following setting means that the regular only the fields \verb|author| and \verb|editor| are considered when doing a selection. \begin{Resources} \rscEqBraces{select.fields}{"author editor"} \end{Resources} Without changing the resource \rsc{select.fields} the command line given previously is equivalent to the (longer) command \sh[-]{select\{\$key "regular\_expression"\}} Note that the resources \rsc{select.case.sensitive} and \rsc{select.fields} are used for all regular expressions following their definition until they are redefined. This means that it is possible to specify that some comparisons are done case sensitive and others are not done case sensitive. Finally the resource \rsc{extract.regex} can be used as in \begin{Resources} \rscEqBraces{extract.regex}{\textit{regular\_expression}} \end{Resources} This is equivalent to specifying a single regular expression to be matched against the key. This feature is kept for backward compatibility only. It is not encouraged and will vanish in a future release. \begin{description} \item[Note] Cross-references are not considered unless \rsc{select.crossrefs} is set. \end{description} \subsection{Extracting and Cross-references}\label{sec:xref} When extracting entries due to contained sub-strings or regular expression matching cross-references are not considered automatically. This behavior can result in incomplete and thus incorrect \BibTeX\ files. The automatic selection of cross-referenced entries can be controlled by the resource \rsc{select.crossrefs}. This resource is \texttt{off} by default. This means that cross-references are ignored. The following instruction can be used to turn on the automatic inclusion of cross-referenced entries: \begin{Resources} \rsc{select.crossrefs} = on \end{Resources} The depth of cross-reference chains can be restricted with the resource \rsc{crossref.limit}. This numeric value limits the depth of the crossreferences. If the actual depth is greater than this value then the cross-referencing is terminated artifically. The default value is 32. \begin{Resources} \rsc{crossref.limit} = 42 \end{Resources} \begin{Summary} \Desc{\opt{x}}{\rsc{extract.file}\{file\}}{Extract the entries from an \texttt{aux} file.} \Desc{}{\rsc{extract.regexp}\{expr\}}{Discouraged backward compatibility command.} \Desc{\opt{X} regex}{\rsc{select}\{spec\}}{Select certain entries according to a regular expression.} \Desc{}{\rsc{select.by.non.string}\{spec\}}{Select certain entries according to a failing sub-string matching.} \Desc{}{\rsc{select.by.string}\{spec\}}{Select certain entries according to a sub-string matching.} \Desc{}{\rsc{select.by.string.ignored}\{chars\}}{Define the class of characters to be ignored by the sub-string matching.} \Desc{}{\rsc{select.case.sensitive}=off}{Turn off the case insensitive comparison.} \Desc{\opt{c}}{\rsc{select.crossrefs}=on}{Turn on the additional selection of cross-referenced entries.} \Desc{}{\rsc{select.fields}\{fields\}}{Determine fields for \opt{X}.} \Desc{}{\rsc{select.non}\{spec\}}{Select certain entries according to a failing regular expression matching.} \end{Summary} %------------------------------------------------------------------------------ \section{Key Generation}\label{sec:key.gen} The key generation facility provides a mean to uniformly replace the reference keys by generated values. Some algorithms are hardwired, namely the generation of short keys or long keys either unconditionally or only when they are needed. Additionally a free formatting facility is provided. This can be used to specify your own algorithm to generate keys. The generation of new keys can be enabled using the command line option \opt{f} in the following way: \sh[f]{format} This command adds format disjunctively to the formatting instructions already given. The same effect can be achieved with the resource \rsc{key.format}. \begin{Resources} \rscEqBraces{key.format}{\textit{format}} \end{Resources} Some values of \textit{format} have a special meaning. Fixed formatting rules are used when one of them is in effect. The special values are described below. To illustrate their results we consider the following \BibTeX{} database entries: \begin{lstlisting}[language=BibTeX] @Unpublished{unpublished-key, author = "First A. U. Thor and Seco N. D. Author and Third A. Uthor and others", title = "This is a rather long title of an unpublished entry which exceeds one line", ... } @Article{, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, ... } @BOOK{whole-collection, editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", title = "High Speed Computer and Algorithm Organization", ... } @MISC{misc-minimal, key = "Missilany", note = "This is a minimal MISC entry" } \end{lstlisting} \begin{description} \item [\rsc{short}] If a field named \verb|key| is present then its value is used. Otherwise if an author or editor field are present, then this field is used. The short version uses last names only. Afterwards a title or booktitle field is appended, after the \rsc{fmt.name.title} separator has been inserted. Finally if all else fails then the default key \rsc{default.key} is used. The result is disambiguated (cf.\ \rsc{key.base}). To see the effect we apply \BibTool{} to the example entries given earlier with the command line argument \verb|-- key.format=short|. This results in the following keys (remaining lines skipped): \begin{lstlisting}[language=BibTeX] @Unpublished{ thor.author.ea:this, @Article{ aamport:gnats, @Book{ lipcoll.lawrie.ea:high, @Misc{ missilany, \end{lstlisting} \item [\rsc{long}] The long version acts like the short version but incorporates initials when formatting names. If \BibTool{} is applied to the example entries given earlier with the command line argument \verb|-- key.format=long| we get the following keys: \begin{lstlisting}[language=BibTeX] @Unpublished{ thor.fau.author.snd.ea:this, @Article{ aamport.la:gnats, @Book{ lipcoll.dj.lawrie.dh.ea:high, @Misc{ missilany, \end{lstlisting} \item [\rsc{new.short}] This version formats like \rsc{short} but only if the given key field is empty. This is obsoleted by the resource \rsc{preserve.keys} and will be withdrawn in a future release. If \BibTool{} is applied to the example entries given earlier with the command line argument \verb|-- key.format=short.need| we get the following keys: \begin{lstlisting}[language=BibTeX] @Unpublished{ unpublished-key, @Article{ aamport:gnats, @Book{ whole-collection, @Misc{ misc-minimal, \end{lstlisting} \item [\rsc{new.long}] This version formats like \rsc{long} but only if the given key field is empty. This is obsoleted by the resource \rsc{preserve.keys} and will be withdrawn in a future release. If \BibTool{} is applied to the example entries given earlier with the command line argument \verb|-- key.format=short.need| we get the following keys: \begin{lstlisting}[language=BibTeX] @Unpublished{ unpublished-key, @Article{ aamport.la:gnats, @Book{ whole-collection, @Misc{ misc-minimal, \end{lstlisting} \item [\rsc{empty}] The empty version clears the key entirely. The result does not conform to the \BibTeX{} syntax rules. This feature can be useful if a resource file must be used which generates only new keys. In this case a first pass can clear the keys and the given resource file can be applied in a second pass to generate all keys. If \BibTool{} is applied to the example entries given earlier with the command line argument \verb|-- key.format=empty| we get the following keys: \begin{lstlisting}[language=BibTeX] @Unpublished{ , @Article{ , @Book{ , @Misc{ , \end{lstlisting} \end{description} In contrast to the command line option, the resource instruction only modifies the formatting specification. The key generation has to be activated explicitly. This can be done using the command line option \opt{F} as in \sh[F]{} Alternatively the Boolean resource \rsc{key.generation} can be used in a resource file: \begin{Resources} \rsc{key.generation} = on \end{Resources} Usually all keys are regenerated. This can have the unpleasant side-effect to invalidate citations in old documents. For this situation the resource \rsc{preserve.keys} is meant. This resource is usually \verb|off|. If it is turned \verb|on| then only those entries receive new keys if they do not have a key already. This means that the input contains only a sequence of white-space characters (which is not accepted by \BibTeX) as in the following example: \begin{lstlisting}[language=BibTeX] @Article{, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, pages = "73+", month = jul, note = "This is a full ARTICLE entry", } \end{lstlisting} Even if \rsc{preserve.keys} is \verb|on|, \BibTool{} still changes all keys to lower case by default. This can be suppressed by switching \rsc{preserve.key.case} to \verb|on| (see section~\ref{sec:parse.pretty}). When the \rsc{key.format} is not \rsc{empty} then the keys are disambiguated by appending letters or numbers. Thus there can not occur a conflict which would arise when two entries have the same key. The disambiguation uses the resource \rsc{key.number.separator}. If a key is found (during the generation) which is already been used then the valid characters from the value of this resource is appended. Additionally a number is added. The appearance of the number can be controlled with the resource \rsc{key.base}. This resource can take the values \rsc{upper}, \rsc{lower}, and \rsc{digit}. The effect can be seen in the following table: \begin{center}% \begin{tabular}{cccc} \textrm{generated key}&\rsc{digit}&\rsc{lower}&\rsc{upper}\\\hline \texttt{key} & \texttt{key} & \texttt{key} & \texttt{key} \\ \texttt{key} & \texttt{key*1} & \texttt{key*a} & \texttt{key*A} \\ \texttt{key} & \texttt{key*2} & \texttt{key*b} & \texttt{key*B} \\ \texttt{key} & \texttt{key*3} & \texttt{key*c} & \texttt{key*C} \\ \texttt{key} & \texttt{key*4} & \texttt{key*d} & \texttt{key*D} \end{tabular} \end{center} As we have seen there are options to adapt the behavior of formatting. Before we explain the free formatting specification in section \ref{sec:key.format} we will present the formatting options. Those options can be activated from a resource file or with the corresponding feature to specify resource instructions on the command line. \begin{description} \item [\rsc{preserve.keys}] This Boolean resource determines whether existing keys should be left unchanged when new keys are generated. The default value is \verb|off|. \item [\rsc{preserve.key.case}] This Boolean resource determines whether keys should be recorded and used exactly as read as opposed to normalizing them by translating all uppercase letters to lower case. The default value is \verb|off|. \item [\rsc{default.key}] The value of this resource is used if nothing else fits. The default value is \verb|**key*|. \item [\rsc{key.base}] The value of this resource is used to determine the kind of formatting the disambiguating number. Possible values are \rsc{upper}, \rsc{lower}, and \rsc{digit}. Uppercase letters, lower case letters, or digits are used respectively. \item [\rsc{key.number.separator}] The value of this resource is used to separate the disambiguating number from the rest of the key. The default value is \verb|*|. \item [\rsc{key.expand.macros}] The value of this Boolean resource is used to indicate whether macros should be expanded while generating a key. The default value is \verb|off|. \item [\rsc{fmt.name.title}] The value of this resource is used by the styles \rsc{short} and \rsc{long} to separate names and titles. The default value is \verb|:|. \item [\rsc{fmt.title.title}] The value of this resource is used to separate words inside titles. The default value is \verb|:|. \item [\rsc{fmt.name.name}] The value of this resource is used to separate different names (where the \BibTeX{} file has \verb|and|) when formatting names. The default value is \verb|.|. \item [\rsc{fmt.inter.name}] The value of this resource is used to separate parts of multi-word names when formatting names. The default value is \verb|-|. \item [\rsc{fmt.name.pre}] The value of this resource is used to separate names and first names when formatting names. The default value is \verb|.|. \item [\rsc{fmt.et.al}] The value of this resource is used to format \verb|and others| parts of a name list. The default value is \verb|.ea|. \item [\rsc{fmt.word.separator}] The value of this resource is used as additional characters not to be considered as word constituents. Word separators are white-space and punctuation characters. Those can not be redefined. The default value is empty. \end{description} The key style \rsc{short} can be formulated in terms of the format specification given in section \ref{sec:key.format} as follows: \begin{lstlisting}[language=BibTool] { { %-2n(author) # %-2n(editor) } { %s($fmt.name.title) %-1T(title) # %s($fmt.name.title) %-1T(booktitle) # } } # { { %s($fmt.name.title) %-1T(title) # %s($fmt.name.title) %-1T(booktitle) } } # %s($default.key) \end{lstlisting} The syntax and meaning of such format specifications is explained in section \ref{sec:key.format}. \subsection{Aliases for Renamed Entries} \BibTool{} provides a means to automatically generate \verb|@Alias| definitions for those entries whoich have received a new key during the key generation. This works for a sufficiently current \BibTeX{} only. The aliases can be requested with the boolean resource \rsc{key.make.alias}. This can be set in a resource file file thie: \begin{Resources} \rsc{key.make.alias} = on \end{Resources} The default is \texttt{off}. This means that no additional entries are created. \begin{Summary} \Desc{}{\rsc{preserve.keys}=off}{Do not generate new keys if one is already present.} \Desc{}{\rsc{preserve.key.case}=on}{Do not translate keys to lower case when reading.} \Desc{}{\rsc{default.key}=\{key\}}{Key used if nothing else applies.} \Desc{}{\rsc{fmt.et.al}=\{ea\}}{String used to abbreviate further names.} \Desc{}{\rsc{fmt.inter.name}=\{s\}}{String used between parts of names.} \Desc{}{\rsc{fmt.name.name}=\{s\}}{String used between names.} \Desc{}{\rsc{fmt.name.pre}=\{s\}}{String separating first and last names.} \Desc{}{\rsc{fmt.name.title}=\{s\}}{String used to separate names from titles.} \Desc{}{\rsc{fmt.title.title}=\{s\}}{String used to separate words in titles.} \Desc{}{\rsc{key.base}=\{base\}}{Kind of numbers or letters for disambiguating keys.} \Desc{}{\rsc{key.expand.macros}=off}{Turn off macro expansion for key generation.} \Desc{\opt{f}}{\rsc{key.format}\{fmt\}}{Set the specification for key generation to \textit{fmt}.} \Desc{\opt{F}}{\rsc{key.generation}=on}{Turn on key generation.} \Desc{}{\rsc{key.make.alias}=on}{Turn on creation of \texttt{@Alias} entries for entries which have received a new key.} \Desc{}{\rsc{key.number.separator}=\{s\}}{String to be used before the disambiguating number.} \end{Summary} %------------------------------------------------------------------------------ \section{Format Specification}\label{sec:key.format} \subsection{Constant Parts} The simplest component of a format is a constant string. Such strings are made up of any character except white-space and the following ten characters \begin{verbatim} " # % ' ( ) , = { } \end{verbatim} This choice of special characters is the same as the special characters of \BibTeX. Since no means is provided to include a special character into a format string we guarantee that the resulting key string is conform to the \BibTeX{} rules. For example the following strings are legal constant parts of a format: \begin{verbatim} Key the_name.of-the-@uthor-is: \end{verbatim} Now we come to explain the meaning of the special characters. The first case consists of the white-space characters. They are simply ignored. Thus the following format strings are equal:\footnote{Well, this is not the whole truth. Internally it makes a difference whether there is a space or not. In the presence of spaces more memory is used. But you shouldn't worry too much about this.} \begin{verbatim} Author Or Editor AuthorOrEditor A u t h o r O r E d i t o r \end{verbatim} \subsection{Formatting Fields}\label{ssec:fields} The next component of formats are made up formatting instructions which are starting with a \texttt{\%} character. The general idea has been inspired by formatting facilities of C. Since there are several different types of information in a \BibTeX{} entry we provide several primitives for formatting. The simplest form is for instance\index{N@\%N} \begin{verbatim} %N(author) \end{verbatim} The \texttt{\%} character is followed by a single character---here \verb|N|---which indicates the way of formatting and the name of the field to be formatted enclosed in parenthesis. The example above requests to format the field \verb|author| according to formatting rules for names (\verb|N|). The general form is \begin{itemize} \item [] \texttt{\%}\textit{sign pre.post qualifier letter}\texttt{(}\textit{field}\texttt{)} \end{itemize} In this specification \textit{sign} is \texttt{+} or \texttt{-}. \texttt{+} means that all characters will be translated to upper case. \texttt{-} means that all characters will be translated to lower case. If no sign is given, the case of the field is preserved. \textit{pre} and \textit{post} are positive integers whose meaning depends on the format letter \textit{letter}. \textit{qualifier letter} is a one letter specification indicating the desired formatting type optionally preceded by the qualifier \verb|#|. Possible values are as described in the following list: \begin{itemize} \item [\texttt{p}] \index{p@\%p|(}Format names according to the format specifier number \textit{post}. In a list of names at most \textit{pre} names are used. If there are more names they are treated as given as \texttt{and others}. \textit{pre} defaults to 2 and \textit{post} defaults to 0. See section~\ref{sec:names} for a description of how to specify name formats. \begin{Example} \begin{lstlisting}[language=BibTeX] author = {A. U. Thor and S. O. Meone and others} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%p(author)} & \texttt{Thor.Meone.ea} \\ \texttt{\%1p(author)} & \texttt{Thor.ea} \\ \texttt{\%-2p(author)} & \texttt{thor.meone.ea} \\ \texttt{\%+1p(author)} & \texttt{THOR.EA} \end{tabular} \end{Example}\index{p@\%p|)} \item [\texttt{n}] \index{n@\%n|(}Format last names only.\\ In a list of names at most \textit{pre} last names are used. If there are more names they are treated as given as \texttt{and others}. If \textit{post} is greater than 0 then at most \textit{post} characters per name are used. Otherwise the whole name is considered. \textit{pre} defaults to 2 and \textit{post} defaults to 0. This is the same as using the \texttt{p} format specifier with the post value of 0. The \textit{post} value of the \texttt{n} specifier is used as the \textit{len} value of the first item of the name format specifier. (See also section~\ref{sec:names}) \begin{Example} \begin{lstlisting}[language=BibTeX] author = {A. U. Thor and S. O. Meone and others} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%n(author)} & \texttt{Thor.Meone.ea} \\ \texttt{\%1n(author)} & \texttt{Thor.ea} \\ \texttt{\%-2n(author)} & \texttt{thor.meone.ea} \\ \texttt{\%+1n(author)} & \texttt{THOR.EA} \\ \texttt{\%.3n(author)} & \texttt{Tho.Meo.ea} \end{tabular} \end{Example}\index{n@\%n|)} \item [\texttt{N}] \index{N@\%N|(}Format names with last names and initials.\\ In a list of names at most \textit{pre} last names are used. If there are more names they are treated as given as \texttt{and others}. If \textit{post} is greater than 0 then at most \textit{post} characters per name are used. Otherwise the whole name is considered. \textit{pre} defaults to 2 and \textit{post} defaults to 0. This is the same as using the \texttt{p} format specifier with the post value of 1. The \textit{post} value of the \texttt{n} specifier is used as the \textit{len} value of the first item of the name format specifier. (See also section~\ref{sec:names}) \begin{Example} \begin{lstlisting}[language=BibTeX] author = {A. U. Thor and S. O. Meone and others} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%N(author)} & \texttt{Thor.AU.Meone.SO.ea} \\ \texttt{\%1N(author)} & \texttt{Thor.AU.ea} \\ \texttt{\%-2N(author)} & \texttt{thor.au.meone.so.ea} \\ \texttt{\%+1N(author)} & \texttt{THOR.AU.EA} \\ \texttt{\%.3N(author)} & \texttt{Tho.AU.Meo.SO.ea} \end{tabular} \end{Example}\index{N@\%N|)} \item [\texttt{d}] \index{d@\%d|(}Format a number, e.g.\ a year.\\ The \textit{post}$^{th}$ number in the field is searched. At most \textit{pre} digits---counted from the right---are used. For instance the field \texttt{"june 1958"} formatted with \texttt{\%2d} results in \texttt{58}. \textit{pre} defaults to a large number except in when the negative sign is present. Then it defaults to 1. \textit{post} defaults to 1. Thus if you want to select the second number you can simply use \texttt{\%.2d} as format specifier. If no number is contained in the field then this specifier fails. Thus the specifier \texttt{\%0d} can be used to check for a number. Positive and negative signs make no sense in specifying translations since numbers have no uppercase or lowercase counterparts. Thus they have a different meaning in this context. If the positive sign is given then the specifier does not fail at all. Instead of failing a single \verb|0| is used. If the negative sign is given then the result is padded with \verb|0| if required. In this case the specifier does not fail at all. Even if no number is found then an appropriate number of \verb|0|s is used. \begin{Example} \begin{lstlisting}[language=BibTeX] pages = {89--123} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%d(pages)} & \texttt{89} \\ \texttt{\%1d(pages)} & \texttt{9} \\ \texttt{\%4d(pages)} & \texttt{89} \\ \texttt{\%-4d(pages)} & \texttt{0089} \\ \texttt{\%-5.2d(pages)} & \texttt{00123} \\ \texttt{\%.3d(pages)} & \textit{fails} \\ \texttt{\%+.3d(pages)} & \texttt{0} \\ \texttt{\%0d(pages)} & \textit{succeeds with empty result} \end{tabular} \end{Example}\index{d@\%d|)} \item [\texttt{D}] \index{D@\%D|(}Format a number.\\ This format specifier acts like the \texttt{d} specifier except that the number is not truncated. Thus a large number comes out complete and not only the last few digits. \begin{Example} \begin{lstlisting}[language=BibTeX] pages = {89--123} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%D(pages)} & \texttt{89} \\ \texttt{\%1D(pages)} & \texttt{89} \\ \texttt{\%4D(pages)} & \texttt{89} \\ \texttt{\%-4D(pages)} & \texttt{0089} \\ \texttt{\%-5.2D(pages)} & \texttt{00123} \\ \texttt{\%.3D(pages)} & \textit{fails} \\ \texttt{\%+.3D(pages)} & \texttt{0} \\ \texttt{\%0D(pages)} & \texttt{89} \end{tabular} \end{Example}\index{D@\%D|)} \item [\texttt{s}] \index{s@\%s|(}Take a field as is (after translation of special characters).\\ At most \textit{pre} characters are used. \textit{pre} defaults to a large number. \begin{Example} \begin{lstlisting}[language=BibTeX] author = {A. U. Thor and S. O. Meone and others} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%s(author)} & \texttt{A.-U.-Thor-and-S.-O.-Meone-and-others} \\ \texttt{\%8s(author)} & \texttt{A.-U.-Th} \\ \texttt{\%-8s(author)} & \texttt{a.-u.-th} \\ \texttt{\%+8s(author)} & \texttt{A.-U.-TH} \\ \texttt{\%0s(author)} & \textit{succeeds with empty result} \end{tabular} \end{Example}\index{s@\%s|)} \item [\texttt{T}] \index{T@\%T|(}Format sentences. Certain words are ignored.\\ At most \textit{pre} words are used. The other words are ignored. If \textit{pre} is 0 then no artificial limit is forced. If \textit{post} is positive then at most \textit{post} letters of each word are considered. Otherwise the complete words are used. New words to be ignored can be added with the resource \rsc{ignored.word}. \textit{pre} defaults to 1 and \textit{post} defaults to 0. \begin{Example} \begin{lstlisting}[language=BibTeX] title = {The Whole Title} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%T(title)} & \texttt{Whole} \\ \texttt{\%2T(title)} & \texttt{Whole-Title} \\ \texttt{\%2.1T(title)} & \texttt{W-T} \\ \texttt{\%-T(title)} & \texttt{whole} \\ \texttt{\%+T(title)} & \texttt{WHOLE} \end{tabular} \end{Example} The string to be formatted according to this specification is separated into words. To accomplish this white-space characters and punctuation characters are considered to be not part of a word but as separator. To add additional word separators use the resource \rsc{fmt.word.separator}. In the following example the characters \verb|+|, \verb|-|, \verb|<|, \verb|=|, \verb|>|, \verb|*|, and \verb|/| are declared as additional word separators. \begin{Resources} \rsc{fmt.word.separator} = {\tt "+-<=>*/"} \end{Resources} Note that the effect of \rsc{fmt.word.separator} is accumulating more characters. It is not possible to define a character not to be a word separator once it has this property.\index{T@\%T|)} \item [\texttt{t}] \index{t@\%t|(}Format sentences. In contrast to the format letter \texttt{T} no words are ignored.\\ At most \textit{pre} words are used. The other words are ignored. If \textit{pre} is 0 then no artificial limit is forced. If \textit{post} is positive then at most \textit{post} letters of each word are considered. Otherwise the complete words are used. \textit{pre} defaults to 1 and \textit{post} defaults to 0. \begin{Example} \begin{lstlisting}[language=BibTeX] title = {The Whole Title} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%t(title)} & \texttt{The} \\ \texttt{\%2t(title)} & \texttt{The-Whole} \\ \texttt{\%2.1t(title)} & \texttt{T-W} \\ \texttt{\%-t(title)} & \texttt{the} \\ \texttt{\%+t(title)} & \texttt{THE} \end{tabular} \end{Example}\index{t@\%t|)} \item [\texttt{W}] \index{W@\%W|(}Format word lists.\\ This specifier acts like \texttt{T} except that nothing is inserted between words. \begin{Example} \begin{lstlisting}[language=BibTeX] title = {The Whole Title} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%W(title)} & \texttt{Whole} \\ \texttt{\%2W(title)} & \texttt{WholeTitle} \\ \texttt{\%2.1W(title)} & \texttt{WT} \\ \texttt{\%-W(title)} & \texttt{whole} \\ \texttt{\%+W(title)} & \texttt{WHOLE} \end{tabular} \end{Example}\index{W@\%W|)} \item [\texttt{w}] \index{w@\%w|(}Format word lists.\\ This specifier acts like \texttt{t} except that nothing is inserted between words. \begin{Example} \begin{lstlisting}[language=BibTeX] title = {The Whole Title} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%w(title)} & \texttt{The} \\ \texttt{\%2w(title)} & \texttt{TheWhole} \\ \texttt{\%2.1w(title)} & \texttt{TW} \\ \texttt{\%-w(title)} & \texttt{the} \\ \texttt{\%+w(title)} & \texttt{THE} \end{tabular} \end{Example}\index{w@\%w|)} \item [\texttt{\#p}] \index{p@\%\#p|(}Count the number of names. If no \textit{sign} is given or the \textit{sign} is \verb|+| then the following rules apply. If the count is less than \textit{pre} or the count is greater than \textit{post} then this specifier fails. Otherwise it succeeds without adding something to the key. The construction \verb|and others|, which indicates an unspecified number of additional authors, counts as one single author. If the \textit{sign} is \verb|-| then the specifier succeeds if and only if the specifier without this sign fails. Thus the \verb|-| acts like a negation of the condition. If post has the value 0 than this is treated like \(\infty\). If \(a\) is the number of names separated by \texttt{and} then\\ \texttt{\%\textit{l}.\textit{h}\#p} succeeds if and only if \(l\leq a\leq h\).\\ \texttt{\%-\textit{l}.\textit{h}\#p} succeeds if and only if \(l>a\) or \(a>h\). \textit{pre} and \textit{post} both defaults to 0. \begin{Example} \begin{lstlisting}[language=BibTeX] author = {A. U. Thor and S. O. Meone and others} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%2\#p(author)} & \textit{succeeds with empty result} \\ \texttt{\%4\#p(author)} & \textit{fails} \\ \texttt{\%-4\#p(author)} & \textit{succeeds with empty result} \\ \texttt{\%3.4\#p(author)} & \textit{succeeds with empty result} \\ \texttt{\%-3.4\#p(author)} & \textit{fails} \end{tabular} \end{Example}\index{p@\%\#p|)} \item [\texttt{\#n}] Is the same as \texttt{\#p}\index{n@\%\#n}. \item [\texttt{\#N}] Is the same as \texttt{\#p}\index{N@\%\#N}. \item [\texttt{\#s}] \index{s@\%\#s|(}Count the number of allowed characters. If no \textit{sign} is given or the \textit{sign} is \verb|+| then the following rules apply. If the count is less than \textit{pre} or the count is greater than \textit{post} then this specifier fails. Otherwise it succeeds without adding something to the key. If the \textit{sign} is \verb|-| then the specifier succeeds if and only if the specifier without this sign fails. Thus the \verb|-| acts like a negation of the condition. If post has the value 0 than this is treated like \(\infty\). \textit{pre} and \textit{post} both default to 0. If \(a\) is the number of allowed characters then\\ \texttt{\%\textit{l}.\textit{h}\#s} succeeds if and only if \(l\leq a\leq h\).\\ \texttt{\%-\textit{l}.\textit{h}\#s} succeeds if and only if \(l>a\) or \(a>h\). \begin{Example} \begin{lstlisting}[language=BibTeX] title = {The Whole Title} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%\#s(title)} & \textit{succeeds with empty result}\\ \texttt{\%13.13\#s(title)} & \textit{succeeds with empty result}\\ \texttt{\%10.16\#s(title)} & \textit{succeeds with empty result}\\ \texttt{\%-10.16\#s(title)} & \textit{fails} \end{tabular} \end{Example}\index{s@\%\#s|)} \item [\texttt{\#w}] \index{w@\%\#w|(}Count the number of words. All words are considered as valid. The division into words is performed after de\TeX{}ing the field. If no \textit{sign} is given or the \textit{sign} is \verb|+| then the following rules apply. If the count is less than \textit{pre} or the count is greater than \textit{post} then this specifier fails. Otherwise it succeeds without adding something to the key. If the \textit{sign} is \verb|-| then the specifier succeeds if and only if the specifier without this sign succeeds. Thus the \verb|-| acts like a negation of the condition. If post has the value 0 than this is treated like \(\infty\). \textit{pre} and \textit{post} both default to 0. If \(a\) is the number of words separated by white-space then\\ \texttt{\%\textit{l}.\textit{h}\#p} succeeds if and only if \(l\leq a\leq h\).\\ \texttt{\%-\textit{l}.\textit{h}\#p} succeeds if and only if \(l>a\) or \(a>h\). \begin{Example} \begin{lstlisting}[language=BibTeX] title = {The Whole Title} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%\#w(title)} & \textit{succeeds with empty result}\\ \texttt{\%3.3\#w(title)} & \textit{succeeds with empty result}\\ \texttt{\%1.6\#w(title)} & \textit{succeeds with empty result}\\ \texttt{\%-1.6\#w(title)} & \textit{fails} \end{tabular} \end{Example}\index{w@\%\#w|)} \item [\texttt{\#t}] \index{t@\%\#t}Is the same as \texttt{\#w}. \item [\texttt{\#W}] \index{W@\%\#W|(}Count the number of words. Certain words are ignored. The ignored words are determined by the resource \rsc{ignored.word}. The division into words is performed after de\TeX{}ing the field. If no \textit{sign} is given or the \textit{sign} is \verb|+| then the following rules apply. If the count is less than \textit{pre} or the count is greater than \textit{post} then this specifier fails. Otherwise it succeeds without adding something to the key. If the \textit{sign} is \verb|-| then the specifier succeeds if and only if the specifier without this sign fails. Thus the \verb|-| acts like a negation of the condition. If post has the value 0 than this is treated like \(\infty\). \textit{pre} and \textit{post} both default to 0. If \(a\) is the number of words separated by white-space which are not marked to be ignored then\\ \texttt{\%\textit{l}.\textit{h}\#p} succeeds if and only if \(l\leq a\leq h\).\\ \texttt{\%-\textit{l}.\textit{h}\#p} succeeds if and only if \(l>a\) or \(a>h\). \begin{Example} \begin{lstlisting}[language=BibTeX] title = {The Whole Title} \end{lstlisting}\vspace{-2ex} With the above item we get the following results: \begin{tabular}{ll} \texttt{\%\#W(title)} & \textit{succeeds with empty result}\\ \texttt{\%2.2\#W(title)} & \textit{succeeds with empty result}\\ \texttt{\%1.6\#W(title)} & \textit{succeeds with empty result}\\ \texttt{\%-1.6\#W(title)} & \textit{fails} \end{tabular} \end{Example}\index{w@\%\#w|)} \item [\texttt{\#T}] \index{T@\%\#T}Is the same as \texttt{\#W}. \end{itemize} If some words are enclosed in brace, they are considered as one composed word. For example, with the format \verb|%t(title)|\index{t@\%t}, and this field: \begin{lstlisting}[language=BibTeX] title = "{The Whole Title}" \end{lstlisting} In this case we obtain \verb|The-Whole-Title|. The field specification \textit{(field)} selects the field of the entry to be formatted. As usual in \BibTeX{} the case of the letters is ignored. If the field does not exist then the formatting fails and continues at the next alternative (see below). But the field is not only sought in the current entry. According to the behavior of \BibTeX{} the special field \texttt{crossref} is taken into account. If a field is missing them the entry named in the \texttt{crossref} field is also considered. Since this dereferencing contains the potential danger of an infinite loop the number of dereferencing steps is restricted by the numeric resource \rsc{crossref.limit}. The number of uses of the \texttt{crossref} field is limited by the value of this resource. The default of this resource is 32. Usually a value of 1 would be sufficient for \BibTeX{} files conforming to the standard styles. Nevertheless other applications can be imagined where a higher value is desirable. To turn off the crossref feature complete you can set the value of \rsc{crossref.limit} to 0. In this case only the fields found in the entry itself are considered. \subsection{Pseudo Fields}\label{sec:pseudo-fields} In addition to the ordinary fields of an entry there are several pseudo fields. They are listed below. \begin{description} \item [\texttt{\$key}]\label{pseudo:key}% This pseudo field contains the old reference key---before generating a new one. If none has been given then the access fails. \item [\texttt{\$sortkey}]% This pseudofield contains the string according to which the sorting is performed. It defaults to the reference key. \item [\texttt{\$default.key}]% This pseudo field contains the value of the resource \rsc{default.key} similarly the resources \rsc{fmt.name.title}, \rsc{fmt.title.title}, \rsc{fmt.name.name}, \rsc{fmt.inter.name}, \rsc{fmt.name.pre}, and \rsc{fmt.et.al} can be accessed. \item [\texttt{\$source}]% This pseudo field contains the name of the file the entry has been read from. If this file can not be determined, e.g. because the entry has been read from stdin, then this pseudo field is empty. \item [\texttt{\$type}]% This pseudo field contains the type of the entry, i.e.\ the string following the initial \texttt{@} of an \BibTeX{} entry, e.g.\ \texttt{article}. It is always present. \item [\texttt{@}\textit{type}]% This pseudo field is matched against the type of the entry. If they are identical (ignoring cases) then the type is returned. Otherwise the access fails. In an article item the specification \texttt{\%s(@Article)}\index{s@\%s} succeeds and returns \texttt{Article} whereas \texttt{\%s(@Book)}\index{s@\%s} fails. \item [\texttt{\$day}]% This pseudo field contains the current day as a two digit number or the empty string if this value is not available. The date and time values are determined at the beginning of the \BibTool{} run and does not reflect the execution time used by \BibTool. On some systems the timing function might be missing or returning strange values. In this case the timing fields simply return the empty string. \item [\texttt{\$month}]% This pseudo field contains the current month as a two digit number or the empty string if this value is not available. \item [\texttt{\$mon}]% This pseudo field contains the current month name as a string or the empty string if this value is not available. \item [\texttt{\$year}]% This pseudo field contains the current year as a four digit number or the empty string if this value is not available. \item [\texttt{\$hour}]% This pseudo field contains the current hour as a two digit number or the empty string if this value is not available. \item [\texttt{\$minute}]% This pseudo field contains the current minute as a two digit number or the empty string if this value is not available. \item [\texttt{\$second}]% This pseudo field contains the current second as a two digit number or the empty string if this value is not available. \item [\texttt{\$user}] % This pseudo field contains the contents of the environment variable \texttt{\$USER} or the empty string if this value is not available. On UN*X systems this variable usually contains the name of the user. This can be used to write logging information into a field. \item [\texttt{\$hostname}]% This pseudo field contains the contents of the environment variable \texttt{\$HOSTNAME} or the empty string if this value is not available. \end{description} \subsection{Conjunctions} Conjunctions are formatting instructions evaluated in sequence. The conjunctions are simply written by successive formatting instructions. A conjunction succeeds if every part succeeds. The empty conjunction always succeeds. Suppose an \BibTeX{} entry contains fields for \texttt{editor} and \texttt{year}. Then the following conjunction succeeds: \begin{itemize} \item [] \texttt{\%-3n(editor) : \%2d(year)} \index{n@\%n}\index{d@\%d} \end{itemize} If the value of the \texttt{editor} field is \verb|"|\verb|E.D. Itor"| and the \texttt{year} field contains \texttt{"1992"} then the result is \texttt{itor:92}. \subsection{If-Then-Else}\label{ssec:if-then-else} Depending on the presence of a (pseudo-) field formatting instructions can be issued. This corresponds to an if-then-else statement in a \textsc{Pascal}-like language. The syntax is as follows: \begin{itemize} \item [] \verb|(|\textit{field}\/\verb|)| \verb|{|\textit{then-part}\/\verb|}| \verb|{|\textit{else-part}\/\verb|}| \end{itemize} If the access to the (pseudo-)field as described in \ref{ssec:fields} succeeds then the \textit{then-part} is evaluated. Otherwise the \textit{else-part} is evaluated. Both parts may be empty. Nevertheless the braces are required. Let us look at an example. The following construction can be used to format a field \texttt{author} if it is present or print a constant string. \begin{itemize} \item [] \verb|(author){|\texttt{\%}\verb|N(author)}{--no-author--}| \index{N@\%N} \end{itemize} \subsection{Alternatives} Alternatives (disjunctives) are separated by the hash mark (\verb|#|). The general form is \begin{itemize} \item [] \textit{alternative\(_1\)} \verb|#| \textit{alternative\(_2\)} \verb|#| \textit{\dots} \verb|#| \textit{alternative\(_n\)} \end{itemize} The alternatives are evaluated from left to right. The first one that succeeds terminates the processing of all alternatives with success. If no alternative is successful then the whole construct fails. An alternative can be empty. The empty alternative succeeds without any other effect. The example given in subsection \ref{ssec:if-then-else} can be also written as \begin{itemize} \item [] \texttt{\%}\verb|N(author) # --no-author--|\index{N@\%N} \end{itemize} If the author field is accessible the first alternative succeeds and terminates the construct. Otherwise the constant string is used. This constant string always succeeds. \subsection{Grouping} Any number of constructs can be enclosed in braces (\verb|{}|) for grouping. Thus the precedence of operators can be bypassed. Coming back to our example from the previous subsection. To complicate the example we want to append an optional title, or a constant string. This is accomplished as follows. \begin{itemize} \item [] \verb|{|\texttt{\%}\verb|N(author) # --no-author-- } |\index{N@\%N} \verb|{|\texttt{\%}\verb|T(title) # --no-title-- } |\index{T@\%T} \end{itemize} The grouping allows to restrict the range of the alternative operator \verb|#| in this example. Another example shows how the alternative together with grouping can be used to share a format specification for certain types of entries: \begin{itemize} \item [] \verb|{|\texttt{\%}\verb|0s(@book) # |\texttt{\%}\verb|0s(@proceedings)} --book-or-proc--|\index{s@\%s} \end{itemize} The \texttt{\%}\verb|0s|\index{s@\%s} specifier is used to check for the existence of a certain field without actually adding anything to the output. Other constructs may serve for the same purpose. This construct is applied to the pseudo fields \texttt{@book} and \texttt{@proceedings}. The access to the pseudo field fails if requested in another type of entry. Those two checks are combined to form a disjunction. Thus the following code---the constant in this example---is reached only if we are in a book or in a proceedings entry. It is not reached in an article. \subsection{Ignored Words} Certain format specifiers act on lists of words. In this situation it can be desirable to ignore certain words. For instance when a sort key is constructed with the title of books it is common practice to omit certain words like articles. This is accomplished by a list of ignored words. This list is initialized at compile time to contain articles of different languages (If the installer has not modified it). The resource \rsc{ignored.word} can be used to put additional words onto the list of ignored words. For this purpose the new word is given as argument to the resource. Note that there should be no space between the braces and the word. For example: \begin{Resources} \rscBraces{ignored.word}{word} \end{Resources} To gain complete control over the list of ignored words you can completely overwrite the compiled in defaults. This can be accomplished by clearing the list of ignored words. Afterwards no word is recognized as ignored word until new words are added to this list. This operation can be performed with the resource \rsc{clear.ignored.words}. In principal this operation does not require any argument. Since this contradicts the syntactic restrictions for resources you have to give an empty argument to this resource: \begin{Resources} \rscBraces{clear.ignored.words}{} \end{Resources} \subsection{Expanding \TeX/\LaTeX{} Macros} When fields are formatted certain \LaTeX{} macros may be replaced by pure text. Each macro not defined is simply ignored. Initially no \LaTeX{} macro is defined. The resource \rsc{tex.define} can be used to define \LaTeX{} macros. The syntax is very close to \LaTeX. The simplest form is the following definition. \begin{Resources} \rscBraces{tex.define}{\textit{macro=replacement text}} \end{Resources} This resource defines a simple macro which is replaced by the replacement text. This replacement text may in turn contain macros. In addition to this simple macro also macros involving arguments can be defined. As in \LaTeX's \verb|\newcommand| the number of arguments is appended after the macro name. \begin{Resources} \rscBraces{tex.define}{\textit{macro}\texttt{[}\textit{arg}\texttt{]=}\textit{replacement text}} \end{Resources} The number of arguments may not exceed 9. The actual parameters are addressed by writing \texttt{\#}\textit{n}, where \textit{n} is the number of the argument. For instance, this feature can be used to ignore certain arguments of macros. Note that spaces between the macro head and the equality sign (\verb|=|) are ignored. Any unwanted spaces after the equality sign may have strange effects. Usually the macro name starts with a backslash (\verb|\|). If the macro name starts with another character then this character is made active (cf.~\cite{knuth:texbook}). This feature is especially useful for translating characters with an extended ASCII code (\(\geq128\)) to the appropriate \TeX{} macros. For instance the following definition forces the expansion of the macro \verb|\TeX| to the string \verb|TeX|. \begin{Resources} \rscBraces{tex.define}{\BS{}TeX=TeX} \end{Resources} Without this definition the title \verb|The \TeX{}book| would result in \verb|book|. With this definition the same title results in \verb|TeXbook|. Suppose you have an input file containing 8-bit characters (e.g. ISO 8859-1 encoding). The following definition can be used to map this character into a pure ASCII string\footnote{To add an e is the German convention for umlaut characters.} \begin{Resources} \rscBraces{tex.define}{{\"u}=ue} \end{Resources} With the following definition the \verb|\protect| macro and the corresponding braces would be ignored when formatting field, otherwise the braces would remain. \begin{Resources} \rscBraces{tex.define}{\BS{}protect[1]=\#1} \end{Resources} Some useful definitions can be found in the libraries distributed with \BibTool{} (see also appendix \ref{chap:resource.files}). \subsection{Name Formatting}\label{sec:names} Names are a complicated thing. \BibTool{} tries to analyze names and ``understand'' them correctly. According to the \BibTeX{} definition a name consists of four types of components: \begin{itemize} \item The first names are any names before the last names which start with an upper case letter.\\ For instance for the name ``Ludwig van Beethoven'' the first name is ``Ludwig''. \item The last name is the last word (or group of words) which does not belong to the junior part.\\ For instance for the name ``Ludwig van Beethoven'' the last name is ``Beethoven''. \item The von part are the names before the last name which start with lower case letters.\\ For instance for the name ``Ludwig van Beethoven'' the von part consists of the word ``van''. \item The junior part of a name is an appendix following the last name. \BibTool{} knows only a small number of words that can appear in the junior part: junior, jr., senior, sen., Esq., PhD., and roman numerals up to XXX. \end{itemize} Everything except the last name is optional. Each part can also consist of several words. More on names can be found in \cite{lamport:latex} and \cite{patashnik:designing}. \BibTool{} provides a means to specify how the various parts of a name should be used to construct a string. This string can be used as part of a key with the \texttt{\%p}\index{p@\%p} format specifier (see above). \BibTool{} uses a small number of name format specifiers.\footnote{The exact number can be changed in the configuration file before compilation. The default is 128.} Initially most of them are undefined. The name format specifier 0 is initially set to the value \verb|%*l[|\emph{fmt.inter.name}\/\verb|]|. The name format specifier 1 is initially set to the value \verb|%*l[|\emph{fmt.inter.name}\/\verb|]%*1f[|\emph{fmt.inter.name}\/\verb|]|. The name format specifiers 0 and 1 are used by the formatting instructions \verb|%N|\index{N@\%N} and \verb|%n|\index{n@\%n}. Thus you should be careful when redefining them. To help you keep an eye on these two name format specifiers \BibTool{} issues a warning when they are modified. The resource \rsc{new.format.type} can be used to assign values to those name format specifiers:\index{f@\%f}\index{v@\%v}\index{l@\%l} \begin{Resources} \rscBraces{new.format.type}{17="\%f\%v\%l"} \end{Resources} This instruction sets the name format specifier number 17 to the given value. This value is a string of characters to be used directly. There is only one construct which is not used literally. This construct is started by a \% sign optionally followed by a \verb|+| or a \verb|-| and a number. Next comes one of the letters \texttt{f}\index{f@\%f}, \texttt{v}\index{v@\%v}, \texttt{l}\index{f@\%f}, or \texttt{j}\index{j@\%j}. Finally there are three optional arguments enclosed in brackets. Thus the general form looks as follows: \begin{itemize} \item [] \texttt{\%}\textit{sign} \textit{len}\texttt{.}\textit{number} \textit{letter} \texttt{[}% \textit{pre}\texttt{][}% \textit{mid}\texttt{][}% \textit{post}\texttt{]} \end{itemize} The letter \texttt{f}\index{f@\%f} denotes all first names. The letter \texttt{l}\index{l@\%l} denotes all last names. The letter \texttt{v}\index{v@\%v} denotes all words in the von part. The letter \texttt{j}\index{j@\%j} denotes all words in the junior part. If \textit{sign} is \verb|+| then the words are translated to upper case. If \textit{sign} is \verb|-| then the words are translated to lower case. If no sign is given then no conversion is performed. If the sign is \verb|*| then the translation is inherited from the calling format. The number \textit{len} can be used to specify the number of characters to be used. Each word is truncated to at most \textit{len} characters if \textit{len} is greater than 0. Otherwise no truncation is performed. Thus a value of \(0\) acts like \(\infty\). Note that the length of the name format specifiers 0 and 1 are automatically inherited from the calling format. The fractional number \textit{number} after the period denotes the number of name parts to be taken into account. This can be used to just show the one first name if more are given. If \texttt{[}\textit{mid}\texttt{]} is given then this string is used between several words of the given part. If none is given then the empty string is used. If \texttt{[}\textit{pre}\texttt{]} is given then this string is used before the given part, but only if the part is not empty. If none is given then the empty string is used. If \texttt{[}\textit{post}\texttt{]} is given then this string is used after the given part, but only if the part is not empty. If none is given then the empty string is used. Now we can come to an example. Suppose the name field contains the value \texttt{Cervantes Saavedra, Miguel de}\footnote{This is the author of ``Don Quixote''}. This name has two last names, one first name and one word in the von part. We want to apply the following name format specifier \begin{itemize} \item [] \verb|%1f[.][][.]|\verb|%1v[.][][.]|\verb|%3l[-]|\verb|%1j| \index{f@\%f}\index{v@\%v}\index{l@\%l} \end{itemize} This means we want to use abbreviation of first name, von and junior part to one letter and of three letters of the last name. Thus we will get the result \verb|M.d.Cer-Saa|. Note that the name specifier does not take care to include only allowed letters into a key. Thus watch out and avoid special characters as white-space and comma. %------------------------------------------------------------------------------ \subsection{Example} To end this section we should have a look at a complete example of key generation specification. For this purpose we define a rule according to which the keys should be generated: \begin{enumerate} \item If a field named \texttt{bibkey} is present then the value of this field should be used. \item If the type of the entry is a book then the authors/editors are used followed by the year separated by a colon. \item If the type of the entry is an article in a journal ({\tt article}) then the author, the journal, the number, and the year should be used. Author and journal should be separated by a colon, The journal should be abbreviated with the initials and separated from number and year by a period. \item If the type of the entry is a volume of conference proceedings (\texttt{proceedings}) then the editor, the first 5 initials of the title and the year should be used. The editor should be followed by a colon and the year preceded by a period. \item If the type of the entry is a contribution in conference proceedings then the author, the initials of the book title and the year should be used. \item Otherwise the first three letters of the type, the author and the year should be used. If no author is given then the initials of the title should be used instead---but at most 6 characters. \end{enumerate} The names should include up to two names abbreviated to four letters and should be translated to lower case. If an information is missing then the respective part together with the following separator should be omitted. The disambiguation should be done by appending upper case letters without a preceding string. If everything else fails three question marks should be inserted as key. To implement this scheme we write the following specification into a resource file: \begin{lstlisting}[language=BibTool] key.expand.macros = on key.base = upper key.number.separator = {} key.format = { %s(bibkey) # %0w(@book) { %-2.4n(author): # %-2.4n(editor): # } { %4d(year) # } # %0w(@article) { %-2.4n(author): # } { %-.1W(journal). # } { %4d(year) # } # %0w(@proceedings) { %-2.4n(editor): # } { %-.1W(title). # %-.1W(booktitle). # } { %4d(year) # } # %0w(@inproceedings) { %-2.4n(author): # } { %-.1W(booktitle). # } { %4d(year) # } # %3s($type)- { %-2.4n(author): # %-6.1W(title). } {%4d(year) # } # %3s($type)- %4d(year) # ??? } \end{lstlisting} Since each part has been explained before we just need some overall remarks. I prefer to use the backtracking-based disjunctions instead of nested if-then-else constructs because they save some braces. They can be read as a switch statement, or even better as a \texttt{cond} statement in Lisp. This means they describe cases. The first successful case terminates the evaluation of the whole cascade. The constructions like \verb|%0w(@book)| are use to distinguish the different types. This construction does not produce any output. It just succeeds or fails depending on the type of the current entry. The \verb|%0w| could also be replaced by other specifiers which serve the same purpose. The constructions like \verb|{%4d(year) # }| always succeed. The hash sign (\verb|#|) catches the failure and inserts the second alternative---which happens to be empty---if the requested field does not exist. \begin{Summary} \Desc{}{\rsc{clear.ignored.words}\{\}}{Forget all words from the list of ignored words.} \Desc{}{\rsc{new.format.type}\{n=spec\}}{Define a new way to format names.} \Desc{}{\rsc{ignored.word}\{s\}}{Add a word to the list of ignored words.} \Desc{}{\rsc{tex.define}\{macro=text\}}{Expand the \TeX{} macro \textit{macro} to \textit{text}.} \Desc{}{\rsc{tex.define}\{macro[n]=text\}}{Expand the \TeX{} macro with arguments.} \end{Summary} %------------------------------------------------------------------------------ \section{Field Manipulation} This sections contains some operations to manipulate fields in some kind. %------------------------------------------------------------------------------ \subsection{Adding Fields} Certain fields can be added. This feature can be used for instance to update time stamps. For this purpose it is important to know that deletion is done before addition. It is also important to know that the newly added entries are not rewritten (see next section) even though rewrite rules are applicable. The resource \rsc{add.field} is provided to perform this operation. \begin{Resources} \rscBraces{add.field}{\textit{field=value}} \end{Resources} This instruction replaces the contents of the field \textit{field} by \textit{value} in each entry. If this field does not exist already then it is added first. The additions are applied in the sequence they are given. \textit{value} can contain formatting instructions already introduced in the section~\ref{ssec:fields} about ``Formatting Fields'' on page~\pageref{ssec:fields}. Suppose a time stamp is stored in the field \texttt{time}. With these resources the update of a time-stamp can be achieved using the resource instructions \begin{Resources} \rscBraces{add.field}{time="June 13, 2000"} \end{Resources} If you want to update all time fields to contain the current date the following instruction can be used. It makes use of the pseudo fields (see page~\pageref{pseudo:key}).\index{s@\%s} \begin{Resources} \rscBraces{add.field}{time="\%s(\$mon) \%s(\$day), \%s(\$year)"} \end{Resources} If you want to strip the month to three leading letters and the year to two trailing digits this can be achieved with the following instruction:\index{s@\%s}\index{d@\%d} \begin{Resources} \rscBraces{add.field}{time="\%3s(\$mon) \%s(\$day), \%2d(\$year)"} \end{Resources} %------------------------------------------------------------------------------ \subsection{Deleting Fields} Certain fields can be deleted. The resource \rsc{delete.field} is provided to perform this operation. The following instruction deletes all fields named \textit{field}: \begin{Resources} \rscBraces{delete.field}{\textit{field}} \end{Resources} %------------------------------------------------------------------------------ \subsection{Renaming Fields} Fields can be renamed during the field rewriting phase. This takes immediate effect such that rewriting rules can fire after the renaming has been performed. The resource \rsc{rename.field} can be used to perform this operation. This resource can be used in the following forms: \begin{Resources} \rscBraces{rename.field}{\textit{old=new}} \rscBraces{rename.field}{\textit{old=new} if \textit{field=pattern}} \end{Resources} The parameters \textit{old} and \textit{new} are the old and the new name of the field. The values are (unquoted) symbols. They are treated case in-sensitive. The final appearance in the output is determined in the printing phase. In the second form a selector is added. \textit{field} is the name of a field or pseudo field (see section~\ref{sec:pseudo-fields}). The value of this field is gathered from the current record and matched against the pattern given as \textit{pattern}. \textit{pattern} is a string value enclosed in double quotes. The matching succeeds if the \textit{pattern} matches a substring of the value of the \textit{field}. If the record does not have such a field then the renaming is not applied. The case-sensitivity of the matching is controlled by the resource \rsc{rewrite.case.sensitive}. The equal signs in the parameter of the resource are optional. They can omitted or written as \#. Note that it is up to you to ensure that double appearing field names are avoided. They would lead to illegal records in the \BibTeX\ output. Note that the selecting pattern is rather restricted at the moment. This might change in the future. The following examples illustrate the function of the resource \rsc{rename.field}. The following rule fixes a typo in the field name. \begin{Resources} \rscBraces{rename.field}{autor = author} \end{Resources} The following rule renames the field \texttt{title} to \texttt{booktitle} for books. All other record types are unaffected. \begin{Resources} \rscBraces{rename.field}{title = booktitle if \$type = "book"} \end{Resources} %------------------------------------------------------------------------------ \subsection{Field Rewriting}\label{sec:field.rewriting} Field modifications can be used to optimize or normalize the appearance of a \BibTeX{} data base. The powerful facility of regular expression matching is used for this purpose as we have already seen in section~\ref{sample.norm}. The resource \rsc{rewrite.rule} can be used to specify rewrite rules. The general form is as follows: \begin{Resources} \rscBraces{rewrite.rule}{field\(_1\) \(\ldots\) field\(_n\) \# pattern \# replacement\_text} \end{Resources} \emph{field\(_1\) \(\ldots\) field\(_n\)} is a list of field names. The rewrite rule is only applied to those fields which have one of those names. If no field name is given then the rewrite rule is applied to all fields. \begin{Resources} \rscBraces{rewrite.rule}{\textit{pattern \# replacement\_text}} \end{Resources} Next there is the separator '\#'. This separator is optional. It can also be the equality sign '='. \emph{pattern} is a regular expression enclosed in double quotes ("). This pattern is matched against sub-strings of the field value---including the delimiters. If a match is found then the matching string is replaced by the replacement text or the field deleted if no replacement text is given. \emph{replacement\_text} is the string to be inserted for the matching sistering of the field value. The backslash '\BS' is used as escape character. '\BS\(n\)' is replaced by the \(n^{th}\)\/ matching group of \emph{pattern}. \(n\)\/ is a single digit (1--9). Otherwise the character following the backslash is inserted.\footnote{Future releases may use backslash followed by letters for special purposes. It is not safe to rely on escaping letters.} Thus it is possible to have double quotes inside the replacement text. Other specials are \begin{itemize} \item [\BS\$] which is replaced by the key of the current entry. \item [\BS @] which is replaced by the type of the current entry. \end{itemize} If no replacement text is given then the whole field is deleted. In fact the instruction \rsc{delete.field} is only an alias for a corresponding rewrite rule with an empty replacement text. This behavior is illustrated in the following abstract examples: \begin{Resources} \rscBraces{rewrite.rule}{\textit{field \# pattern}} \rscBraces{rewrite.rule}{\textit{pattern}} \end{Resources} More concrete, the rewrite rule \begin{Resources} \rscBraces{rewrite.rule}{ time \# "\Hat\(\{\}\)\$" } \end{Resources} deletes the time field if the value of the field is empty and enclosed in curly braces. This is checked with the anchored regular expression \texttt{\^{}\(\{\}\)\$}. The hat \verb|^| matches the beginning of the value and the dollar \texttt{\$} matches its end. Since nothing is in between---except the field delimiters---the rule is applied only to time fields with empty contents. This can be generalized to the following rewrite rule which deletes all empty fields using the same mechanism and just omitting the specification of a field name: \begin{Resources} \rscBraces{rewrite.rule}{ "\Hat\(\{\}\)\$" } \end{Resources} Note that for a similar kind of rule for double quotes as field delimiters you need to quote these characters with backslashes: \begin{Resources} \rscBraces{rewrite.rule}{ "\Hat\BS"\BS"\$" } \end{Resources} The replacement text may contain field formatting instructions as described in section~\ref{ssec:fields} on page~\pageref{ssec:fields}. These field formatting instructions are replaced by their respective values. Thus we could exploit again the time stamp example from above. The following rewrite rule will update an existing time stamp without adding one if none is present: \begin{Resources} \rscBraces{rewrite.rule}{ time ".*" = "\%3s(\$mon) \%s(\$day), \%2d(\$year)" }\index{s@\%s}\index{d@\%d} \end{Resources} The pattern \verb|.*| matches any sequence of arbitrary characters. Thus the old contents of the field is a match. In this example the value is not reused in the replacement text. Thus the old contents is completely replaced by the new one. Usually the matching is done case insensitive. This means that any upper case letter matches its lower counterpart and vice versa. This behavior is controlled by the Boolean resource \rsc{rewrite.case.sensitive} which is \rsc{on} by default. Changing this variable influences only rewrite rules specified later. \begin{Resources} \rsc{rewrite.case.sensitive} = off \end{Resources} A problem occurs e.g. when a string is replaced by a string containing the original one. To avoid infinite recursion in such cases the numeric resource \rsc{rewrite.limit} controls the number of applications of each rewrite rule. If the number given in \rsc{rewrite.limit} is not negative and this limit is exceeded then a warning is printed and further applications of this rule are stopped. A negative value of the resource \rsc{rewrite.limit} indicates that no limitation should be used. Next we will investigate some concrete examples. Note that in these examples the character '\texttt{\symbol{32}}' denotes a single space. It is used to highlight places where spaces have to be used which would be hard to recognize otherwise. \begin{itemize} \item Empty entries are composed of delimiters --- either double quotes or curly braces which enclose an arbitrary number of spaces. If we want to delete empty entries we can use the following two rules. \begin{Resources} \rscBraces{rewrite.rule}{\texttt{ "\symbol{"5E}\symbol{"5C}"\symbol{32}*\symbol{"5C}"\$" }} \rscBraces{rewrite.rule}{\texttt{ "\symbol{"5E}\symbol{"7B}\symbol{32}*\symbol{"7D}\$" }} \end{Resources} The caret '\texttt{\symbol{"5E}}' denotes the beginning of the whole string and the dollar is its end. The star is an operator which says that an arbitrary number of the preceding regular expression --- i.e.\ the space --- can occur at this point. \item Ranges of pages should usually be composed of numbers separated by an n-dash (\texttt{-{}-}). The next example shows how the pages field can be normalized. Spaces are deleted and a single minus sign is replaced by a double minus. \begin{Resources} \rscBraces{rewrite.rule}{\texttt{ pages \# "\symbol{"5C}(\symbol{"5B}0-9\symbol{"5D}+\symbol{"5C})\symbol{32}*-\symbol{32}*\symbol{"5C}(\symbol{"5B}0-9\symbol{"5D}+\symbol{"5C})" = "\symbol{"5C}1--\symbol{"5C}2" }} \end{Resources} \item Field rewriting may be used to remove \LaTeX{} commands. This example shows how to remove from titles a {\tt\char"5C protect} macro together with the braces, in case the delimiter is a double quote. \begin{Resources} \rscBraces{rewrite.rule}{\tt title \# "\char"5E\char"5C"\char32*\char"5C\char"5C \char32*protect\char32*\char"7B \char"5C(.*\char"5C)\char"7D\char"5C"\$" = "\symbol{"5C}"\symbol{"5C}1\char"5C"" } \end{Resources} \end{itemize} %------------------------------------------------------------------------------ \subsection{Field Ordering} Fields can be reordered within an entry. This feature is controlled by the presence of a specification for the order to use. The order is specified with the resource \rsc{sort.order}. The general form is as follows: \begin{Resources} \rscBraces{sort.order}{ \textit{entry = field\(_1\) \# field\(_2\) \# ...} } \end{Resources} \emph{entry} is the name of an entry like \texttt{book}. The \emph{field}s are an arbitrary number of field names like \texttt{author}. This specification says that \emph{field1} should precede \emph{field2} etc. Fields which are not in this list are arranged after the specified ones. The are left in the same order as they appear in the entry. Another possibility is to specify the entry \texttt{*}. Such a sorting order is applicable to any kind of entry. If no specific sort order is found then this general order is used if one has been specified. Any sorting order is added to a list of sorting orders if it has not been defined before. If a sorting order is specified again, the old one is simply overwritten. Consider the following part of a resource file: \begin{Resources} \rscBraces{sort.order}{* = author \# title} \rscBraces{sort.order}{misc = author \# title \# howpublished \# year \# month \# note} \end{Resources} This means that the author field goes before the title field in any entry type. For the misc entries additional specifications are made. The library \file{sort\_fld.rsc} contains a sample sorting order for the standard entry types. \begin{Summary} \Desc{}{\rsc{add.field}\{field=value\}}{Add a new field to each entry.} \Desc{}{\rsc{delete.field}\{field\}}{Delete the named field from all entries.} \Desc{}{\rsc{rename.field}\{old=new\}}{Rename a field.} \Desc{}{\rsc{rename.field}\{old=new if field=pattern\}}{Rename a field if the record satisfies a certain condition.} \Desc{}{\rsc{rewrite.case.sensitive}=off}{Turn off the case comparison during field rewriting.} \Desc{}{\rsc{rewrite.rule}\{fields\#pattern\#text\}}{Replace in all given fields the pattern by the replacement text.} \Desc{}{\rsc{sort.order}=\{entry=f\#\ldots\#f\}}{Specify a preference order for fields in a given entry.} \end{Summary} %------------------------------------------------------------------------------ \section{Semantic Checks} Semantic checks can be enabled in addition to the syntactic checks performed during parsing. \subsection{Finding Double Entries} When merging several bibliographic data bases a common problem is the occurrence of doubled entries in the resulting data base. When searching for double entries several problems arise. Which entries should be considered equal and what should happen to double entries. The first question is answered as follows. Two entries are considered equal if their sort key is identical and they are adjacent in the final output. The first condition of identical sort keys allows the user to specify which criteria should be used when comparing entries. This can be achieved with the resource \rsc{sort.format} (see section \ref{sorting}). The second condition can easily be achieved by also sorting when requesting checking of doubles. It remains the question what to do with the doubles. Usually it is not desirable to keep double entries in one data base, so only one entry found is kept. The others are printed as comments, i.e.\ the initial ``@'' is replaced by ``\#\#\#''. Thus all information is still present but inactive in the \BibTeX{} file. However, further processing with \BibTool{} will remove these entries if \rsc{pass.comments} is \rsc{off}, which is the default. Sometimes it is not desirable to include deleted entries in the output -- not even as comments. In this case the default behavior can be changed with the help of the Boolean resource \rsc{print.deleted.entries}. If this resource is \rsc{off} then deleted entries are suppressed completely. The prefix for deleted entries is stored in the resource \rsc{print.deleted.prefix} which defaults to ``\#\#\#''. Thus it can be redefined. However note that you should avoid using a string ending in an at sign \texttt{@} since this would undo the effect of deleting an entry. The Boolean resource \rsc{check.double.delete} can be used to delete double entries completely. For this purpose it has to be turned off as in: \begin{Resources} \rsc{check.double.delete} = on \end{Resources} The resource \rsc{check.double} can be used to turn on the checking of doubles. This feature is turned off initially. \begin{Resources} \rsc{check.double} = on \end{Resources} Checking of doubles can also be turned on with the command line option \opt{d}: \sh[d]{} \subsection{Regular Expression Checks} The regular expressions (see section \ref{sec:regex}) which are used to rewrite fields (see section \ref{sec:field.rewriting}) can also be used to perform semantic checks on fields. For this purpose the resource \rsc{check.rule} is provided. The syntax of \rsc{check.rule} is the same as for \rsc{rewrite.rule}. \begin{Resources} \rscBraces{check.rule}{ \textit{field \# pattern \# message} } \end{Resources} Again \emph{field} and \emph{message} is optional. The separator \# can also be written as equality sign (=) or omitted. Each field is processed as follows. Each check.rule is tried in turn until one rule is found where \emph{field} (if given) is identical to the field name and \emph{pattern} matches a sub-string of the field value. If such a rule is found then the \emph{message} is written to the error stream. If no message is given then nothing is printed and processing of the current field is ended. \emph{message} is treated like the replacement text in \rsc{rewrite.rule}, Thus the special character combinations described in section \ref{sec:field.rewriting} are expanded. Usually the matching is not done case sensitive. This means that any upper case letter matches its lower counterpart and vice versa. This behavior is controlled by the Boolean resource \rsc{check.case.sensitive} which is ON by default. Changing this variable influences only rewrite rules as described in section~\ref{sec:field.rewriting}. \begin{Resources} \rsc{check.case.sensitive} = off \end{Resources} Consider the following example. We want to check that the year field contains only years from 1800 to 1999. Additionally we want to allow two digit abbreviations. \begin{Resources} \rscBraces{check.rule}{\texttt{ year "\Hat[\BS"\symbol{"7B}]1[89][0-9][0-9][\BS"\symbol{"7D}]\$" }} \rscBraces{check.rule}{\texttt{ year "\Hat[\BS"\symbol{"7B}][0-9][0-9][\BS"\symbol{"7D}]\$" }} \rscBraces{check.rule}{\texttt{ year "" "\BS@ \BS\$: Year has to be a suitable number" }} \end{Resources} The first rule matches any number starting with 1 followed by 8 or 9 and finally two digits. The whole number may be enclosed in double quotes or curly braces.\footnote{In fact the regular expression allows also strings starting with a quote and ending in a curly brace. But this syntactical nonsense is ruled out by the parser already.} The hat at the beginning and the dollar at the end force that the pattern matches against the whole field value only. The next rule covers years consisting of two digits. The first two rules produce no error message but end the search for further matches. Thus is something suitable is found then one of the first two rules finds it. Otherwise we have to produce an error message. This is done with the third rule. The empty pattern matches against any value of the year field. This rule is only applied if the preceding rules do not match. In this case we print an error message. \texttt{\BS@} is replaced by the current type and \texttt{\BS\$} by the current key. \begin{Summary} \Desc{}{\rsc{check.case.sensitive}=off}{Perform semantic checks case sensitive.} \Desc{\opt{d}}{\rsc{check.double}=on}{Find and mark or delete entries with identical sort keys.} \Desc{}{\rsc{check.double.delete}=on}{Delete double entries instead of deactivating them.} \Desc{}{\rsc{check.rule}\{field\#pattern\#msg\}}{If the value of field matches pattern then print the given message.} \end{Summary} %------------------------------------------------------------------------------ \section{Strings --- also called Macros}\label{sec:macros} Strings in \BibTeX{} files play an important role when managing large bibliographic data bases. Thus the deserve special treatment. If the resource \rsc{macro.file} is defined then the macros are written to this file. The argument is a file name as in \begin{Resources} \rscBraces{macro.file}{\textit{macro/file/name}} \end{Resources} Note that the reverse operation to string export namely the import of strings does not deserve special treatment. You can simply give the macro file as one of the input files---preferably before any input file that makes use of one of the macros contained therein. The Boolean resource \rsc{print.all.strings} indicates if all macros defined in the \BibTeX{} file should be printed or only those macros actually used. \begin{Resources} \rsc{print.all.strings} = on \end{Resources} The appearance of string names is controlled by the resource \rsc{symbol.type} (see \pageref{symbol.type}). Strings can be expanded when printing entries. This feature of \BibTool{} is controlled by the resource \rsc{expand.macros} as in \begin{Resources} \rsc{expand.macros} = on \end{Resources} The effect is that all known strings in normal entries are replaced by their values. If the values are not defined at the time of expansion then the macro name remains untouched. As a side effect strings concatenations are simplified. Imagine the following \BibTeX{} file. \begin{lstlisting}[language=BibTeX] @string{ WGA = " World Gnus Almanac" } @Book{ almanac-66, title = 1967 # WGA, month = "1~" # jan } \end{lstlisting} If \BibTool{} is applied with \rsc{expand.macros} turned on this results in the following output --- if the default settings are used for every other resource. \begin{lstlisting}[language=BibTeX] @STRING{wga = " World Gnus Almanac" } @Book{ almanac-66, title = {1967 World Gnus Almanac}, month = {1~} # jan } \end{lstlisting} The macro \texttt{WGA} has been expanded and merged with \verb|1967|. Note that the string \verb|jan| has not been expanded since the value should be defined in a \BibTeX{} style file (\file{.bst}). When macros are expanded the delimiters of entries are normalized, i.e.\ only one style is used. In this example braces have been used. The alternative would be to use double quotes. This behavior is controlled by the resource \rsc{print.braces}. If this resource is on then braces are used otherwise double quotes are taken. It can be changed like in \begin{Resources} \rsc{print.braces} = off \end{Resources} The delimiters of the whole entry are recommended to be braces. For compatibility with Scribe it is also allowed that parentheses are used for those delimiters. This behavior can be achieved with the Boolean resource \rsc{print.parentheses}. Initially this resource is off. It can be set like in the following instruction: \begin{Resources} \rsc{print.parentheses} = on \end{Resources} \begin{Summary} \Desc{\opt{m} \textit{file}}{\rsc{macro.file}=\{file\}}{Write the macro definitions to the file \textit{file}.} \Desc{}{\rsc{print.all.strings}=off}{Print only those macro definitions which are used instead of all.} \Desc{}{\rsc{expand.macros}=on}{Turn on macro (string) expansion in fields.} \Desc{}{\rsc{print.braces}=off}{Switch to the use of quotes for expanded macros instead of braces.} \Desc{}{\rsc{print.parentheses}=on}{Enclose the whole entry in parentheses instead of braces.} \end{Summary} %------------------------------------------------------------------------------ \section{Statistics} Some information can be obtained at the end of a \BibTool{} run. The number of \BibTeX{} items read and written is printed. To enable this feature the resources \rsc{count.all} and \rsc{count.used} are provided. \begin{Resources} \rsc{count.all} = on \end{Resources} \rsc{count.all} indicates that all known types of \BibTeX{} items should be listed. \begin{Resources} \rsc{count.used} = on \end{Resources} \rsc{count.used} forces only those types of \BibTeX{} items to be listed which have been found in the input files. \begin{Summary} \Desc{\opt{\#}}{\rsc{count.all}=on}{Print statistics about all known entry types.} \Desc{\opt{@}}{\rsc{count.used}=on}{Print statistics about the used entry types only.} \end{Summary} %------------------------------------------------------------------------------ \section{\BibTeX1.0 Support} \BibTool\ supports already some of the feature proposed for \BibTeX1.0. %------------------------------------------------------------------------------ \subsection{Including Bibliographies} The bibliography file may contain an instruction of the following form: \begin{lstlisting}[language=BibTeX] @include{abc.bib} \end{lstlisting} Such an entry is stored in the database and printed when requested. Nevertheless the resource \rsc{apply.include} can be used to control this behavior. %------------------------------------------------------------------------------ \subsection{Aliases} The bibliography file may contain an instruction of the following form: \begin{lstlisting}[language=BibTeX] @alias{abc=def} \end{lstlisting} This means that the key \texttt{abc} is treated as an alias for the key \texttt{def}. Usually this alias is stored as alias in the database. For old \BibTeX\ files it may be desirable to eliminate aliases and introduce copies of records instead. Nevertheless the resource \rsc{apply.alias} can be used to control this behavior. %------------------------------------------------------------------------------ \subsection{Modifications} The bibliography file may contain an instruction of the following form: \begin{lstlisting}[language=BibTeX] @modify{key, abc = {def} } \end{lstlisting} This modification is stored in the database without being applied. Nevertheless the resource \rsc{apply.modify} can be used to control this behavior. \begin{Summary} \Desc{}{\rsc{apply.alias}=on}{Expand the aliased entries in the database.} \Desc{}{\rsc{apply.include}=on}{Include the entries contained in the bibliography file given in \texttt{@include}.} \Desc{}{\rsc{apply.modify}=on}{apply the modifies in the database.} \end{Summary} %------------------------------------------------------------------------------ %------------------------------------------------------------------------------ \chapter{Limitations} \section{Limits of \BibTool} \BibTool{} has been written with dynamic memory management wherever possible. Thus \BibTool{} should be limited by the memory available only. Especially the limitation on the field length which is present in \BibTeX\,0.99 is not present in \BibTool. \BibTeX{} needs a special order when cross-referenced entries are used. This limitation has also been released in \BibTool. \section{Bugs and Problems} Problems currently known are the following ones. They are not considered to be bugs. \begin{itemize} \item The referencing feature of \BibTeX{} is not supported. \verb|\cite| macros can be contained in fields (e.g. notes). Such things can be confused. \item The memory management uses dynamic memory. This memory is reused but not returned to the operating system. Thus \BibTool{} may run out of memory even if a more elaborated memory management may find free memory. This is a design decision and I don't think that I will change it. \item The \TeX{} reading apparatus is only imitated to a certain limit. But this should be enough for most applications to produce satisfactory results. \item In several modules ASCII encoding is assumed. I do not know to which extend this influences the functionality since I don't have access to non-ASCII machines. \item Macro expansion uses a dynamic array which can turn out to be too short. This will be corrected as soon as I have an example where this bug shows up. \end{itemize} The distribution of \BibTool{} also contains a file named \file{ToDo}. If you are interested in more detailed descriptions of possible problems, limitations, and ideas for improvements in further releases then you can have a look at the contents of this file. %------------------------------------------------------------------------------ %------------------------------------------------------------------------------ \chapter{Sample Resource Files}\label{chap:resource.files} Sample resource files are included in the distribution of \BibTool{} in the directory \file{lib}. Only some of them are reproduced in this section. \section{The Default Settings} The following list shows the defaults for all resource instructions. \begin{lstlisting}[language=BibTool] apply.alias = off apply.include = off apply.modify = off bibtex.env.name = "BIBINPUTS" check.case.sensitive = on check.double = off check.double.delete = off count.all = off count.used = off crossref.limit = 32 default.key = "**key*" dir.file.separator = "/" env.separator = ":" expand.macros = on fmt.et.al = ".ea" fmt.inter.name = "-" fmt.name.name = "." fmt.name.pre = "." fmt.name.title = ":" fmt.title.title = "-" ignored.word = "{a}" ignored.word = "{a}n" ignored.word = "the" ignored.word = "le" ignored.word = "les" ignored.word = "la" ignored.word = "{}un" ignored.word = "{}une" ignored.word = "{}el" ignored.word = "{}il" ignored.word = "der" ignored.word = "die" ignored.word = "das" ignored.word = "{}ein" ignored.word = "{}eine" key.base = lower key.expand.macros = on key.format = short key.generation = off key.make.alias = off key.number.separator = "*" new.entry.type = "{}Article" new.entry.type = "Book" new.entry.type = "Booklet" new.entry.type = "Conference" new.entry.type = "{}InBook" new.entry.type = "{}InCollection" new.entry.type = "{}InProceedings" new.entry.type = "Manual" new.entry.type = "MastersThesis" new.entry.type = "Misc" new.entry.type = "PhDThesis" new.entry.type = "Proceedings" new.entry.type = "TechReport" new.entry.type = "{}Unpublished" preserve.keys = off preserve.key.case = off print.align = 18 print.align.string = 18 print.align.preamble = 11 print.align.comment = 10 print.align.key = 18 print.braces = on print.comma.at.end = on print.all.strings = on print.deleted.prefix = "\#\#\#" print.deleted.entries = on print.entry.types = "pisnmac" print.equal.right = on print.indent = 2 print.leading.comma = off print.line.length = 77 print.newline = 1 print.parentheses = off print.terminal.comma = off print.use.tab = on print.wide.equal = off rewrite.case.sensitive = on rewrite.limit = 512 quiet = off select.case.sensitive = off select.crossrefs = off select.field = "\$key" sort = off sort.cased = off sort.format = "\%s(\$key)"\index{s@\%s} sort.macros = on sort.reverse = off suppress.initial.newline = off symbol.type = lower verbose = off \end{lstlisting} \section{Useful Translations} The resource file \verb|tex_def| translates international characters into plain text representations. Especially the German umlaut sequences are translated. For instance the letter {\"A} which is written as \verb|{\"A}| in a \BibTeX{} file is translated to \verb|Ae|.\footnote{Note that the short notation of \texttt{german.sty} or \texttt{babel} is not understood by \BibTeX{} nor by \BibTool. } Additionally some logos are defined. \begin{lstlisting}[language=BibTool] tex.define {\"[1]=#1e} tex.define {\ss=ss} tex.define {\AE=AE} tex.define {\OE=OE} tex.define {\aa=aa} tex.define {\AA=AA} tex.define {\o=o} tex.define {\O=O} tex.define {\l=l} tex.define {\L=L} tex.define {\i=i} tex.define {\j=j} tex.define {\TeX=TeX} tex.define {\LaTeX=LaTeX} tex.define {\LaTeXe=LaTeX2e} tex.define {\BibTeX=BibTeX} tex.define {\AMSTeX=AMSTeX} \end{lstlisting} \section{Other Resource Files} The distribution contains additional resource files. Some of them are sketched here. Others may be contained in the distribution as well. Look in the appropriate directory. \begin{description} \item [\file{iso2tex}]\ \\ define rewrite rules to translate ISO 8859-1 characters into \BibTeX\ compatible sequences. \item [\file{iso\_def}]\ \\ define macro equivalents for ISO 8859-1 characters into \TeX{} compatible sequences. \item [\file{sort\_fld}]\ \\ defines a sort order for the common \BibTeX\ entry types. \item [\file{check\_y}]\ \\ contains a sample for semantic checks. The year field is checked to be a suitable number. \item [\file{month}]\ \\ tries to introduce \BibTeX\ strings for month names. Provisions are made to preserve other information contained in the month field. \item [\file{opt}]\ \\ copes with \texttt{OPT} prefixes as introduced e.g. by bibtex-mode. \item [\file{braces}]\ \\ tries to replace double quotes as field delimiters by braces. \end{description} %------------------------------------------------------------------------------ \bibliographystyle{alpha} \bibliography{bibtool} \ifHTML\else \ifx\ptt\undefined\global\let\ptt\tt\fi \ifx\psf\undefined\global\let\psf\sf\fi \ifx\pdollar\undefined\global\let\pdollar\$\fi \fi \printindex \end{document} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Local Variables: % mode: latex % TeX-master: nil % fill-column: 78 % End: BibTool/doc/bibtool.bib0000644000175100017510000000255112646423402013713 0ustar genegene%%*** bibtool.bib ************************************************************* %% %% This file is part of BibTool. %% It is distributed under the Creative Commons Attribution-Share %% Alike 3.0 License. %% %% (c) 1995-2016 Gerd Neugebauer %% %% Net: gene at gerd-neugebauer.de %% %%***************************************************************************** @Book{ knuth:texbook, author = "Donald E. Knuth", title = "The \TeX{}book", publisher = "Addison-Wesley Publishing Company", year = 1989, edition = "15th" } @Book{ goosens.mittelbach.ea:companion, author = "Michel Goosens and Frank Mittelbach and Alexander Samarin", title = "The \LaTeX{} companion", publisher = "Addison-Wesley Publishing Company", year = 1994, optnote = "" } @Book{ lamport:latex, author = "Leslie Lamport", title = "{\LaTeX}: A Document Preparation System", publisher = "Addison-Wesley Publishing Company", year = "1994", edition = "2nd" } @Manual{ patashnik:bibtexing, title = "\BibTeX{}ing", author = "Oren Patashnik", OPTorganization="", OPTaddress = "", OPTedition = "", year = 1988, OPTmonth = "", OPTnote = "" } @Manual{ patashnik:designing, title = "Designing \BibTeX{} Styles", author = "Oren Patashnik", OPTorganization="", OPTaddress = "", OPTedition = "", year = 1988, OPTmonth = "", OPTnote = "" } BibTool/doc/bibtool.ist0000644000175100017510000000030210562442147013750 0ustar genegenepreamble "\\begin{theindex}\\footnotesize\n" lethead_prefix " \\medskip\\par{\\Large\\bf " lethead_suffix "}\n" lethead_flag 1 delim_0 " \\dotfill " delim_1 " \\dotfill " delim_2 " \\dotfill " BibTool/doc/bibtool-doc.sty0000644000175100017510000000406612646422502014544 0ustar genegene%%*** bibtool-doc.sty ********************************************************* %% %% This file is part of BibTool. %% It is distributed under the Creative Commons Attribution-Share %% Alike 3.0 License. %% %% (c) 2011-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %%***************************************************************************** \ProvidesPackage{bibtool-doc} \RequirePackage{color} \RequirePackage{makeidx} \RequirePackage{booktabs} \RequirePackage[colorlinks=true, linkcolor=blue, urlcolor=blue, filecolor=blue, citecolor=blue]{hyperref} \DeclareRobustCommand\BibTool{\textsc{Bib\hskip-.1em\-% \mbox{T\hskip-.15emo\hskip-.05emo\hskip-.05eml}}} \DeclareRobustCommand\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em\TeX}} \renewcommand\maketitle{\thispagestyle{empty} \null\vfill \begin{center} \rule{\textwidth}{5pt}% \bigskip\par \hbox to \textwidth{\cminch \hss B\hss I\hss B\hss T\hss O\hss O\hss L\hss} \medskip\par\normalsize \mbox{}\rfill{5pt}\ A Tool to Manipulate \BibTeX\ Files\ \rfill{5pt}\null \medskip\par\normalsize Version \Version \vfill {\Huge\bf \@title}\vfill \textit{\LARGE\@author} \end{center} \vfill\vfill } \newenvironment{Abstract}{\begin{center}\begin{minipage}{.8\textwidth}\small \begin{center}\textbf{Abstract}\end{center}\par }{\end{minipage}\end{center}\vfill\vfill} \newif\ifHTML \HTMLfalse \renewcommand\ps@headings{\let\@mkboth\markboth \def\@oddfoot{}\def\@evenfoot{} \def\@evenhead{\vbox{\vss\hbox to \textwidth{\rm\thepage \hss {\scriptsize\sc\ \leftmark}}\kern 1.5mm\hrule depth 0.2 true pt}} \def\@oddhead{\vbox{\vss\hbox to \textwidth{\rm{\scriptsize\sc \rightmark\ } \hss \thepage}\kern 1.5mm\hrule depth 0.2 true pt}} \def\chaptermark##1{\markboth {\ifnum \c@secnumdepth>\m@ne \thechapter. \ \fi ##1}{}} \def\sectionmark##1{\markright {\ifnum \c@secnumdepth >\z@ \thesection. \ \fi ##1}}} \pagestyle{headings} \addtolength{\headheight}{2pt} \parskip=1ex plus 1ex \parindent=0pt % BibTool/doc/ref_card.tex0000644000175100017510000003004712646422630014075 0ustar genegene%%*** ref_card.tex ************************************************************ %% %% This file is part of BibTool. %% It is distributed under the Creative Commons Attribution-Share %% Alike 3.0 License. %% %% (c) 1996-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %%----------------------------------------------------------------------------- %% Usage: latex ref_card %%***************************************************************************** \documentclass[a4paper]{article} \usepackage{multicol} \usepackage[landscape]{geometry} \usepackage[colorlinks=true, linkcolor=blue, urlcolor=blue, filecolor=blue, citecolor=blue]{hyperref} \input{config.tex} \hypersetup{pdftitle={BibTool Quick Reference Card}} \hypersetup{pdfauthor={Gerd Neugebauer}} \hypersetup{pdfsubject={Version \Version}} \oddsidemargin = -10mm \evensidemargin = -10mm \topmargin = -10mm \advance\textwidth 60mm \advance\textheight 34mm \headsep = 0pt \headheight = 0pt \parsep = 0pt \parindent = 0pt \parskip = 0pt \pagestyle{empty} \newcommand\BibTool{{\sc Bib\hskip-.1em T\hskip-.15emo\hskip-.05emo\hskip-.05eml}} \newcommand\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} \newenvironment{FlatList}{\begin{list}{}{% \topsep=0pt\itemsep=0pt\parsep=0pt\let\makelabel=\flatlistlabel}}{\end{list}}% \newcommand\flatlistlabel[1]{\descriptionlabel{\sf #1}} \newcommand\Arg[1]{{\rm\{}{\sl #1}{\rm\}}} \newcommand\ARG[1]{{\sl #1}} \newcommand\OnOff{{\sl OnOff}} \newcommand\Num{{\sl n}} \newcommand\Section[1]{\begin{center}\normalsize\bf #1\end{center}\nobreak } \newcommand\Lib[1]{{\tt #1}} \newcommand\mailto[1]{\href{mailto:#1}{\tt #1}} \newcommand\link[1]{\href{#1}{\tt #1}} \newcommand\NewPage{\end{multicols} \vfill\vfill\vfill \begin{center}\rule{.8\textwidth}{.1pt}\end{center} \newpage \begin{center}\rule{.8\textwidth}{.1pt}\end{center}\vfill \begin{multicols}{4} } \begin{document} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{center} \Large \BibTool{} Quick Reference Card \\[.5ex] \scriptsize for \BibTool{} version \Version{} --- see also \link{http://www.gerd.neugebauer.de/software/TeX/BibTool/} \\ \copyright\Year{} Gerd Neugebauer (\mailto{gene@gerd-neugebauer.de}) \\ \rule{.80\textwidth}{.1pt} \end{center} \vfill \footnotesize\rm \begin{multicols}{4} \Section{Command line options} \begin{FlatList} \item [-{}- \ARG{rsc\_command}]\ \\ Perform resource command as if given in a file. \item [-A \ARG{type}]\ \\ Determine key disambiguation. \ARG{type} in {\tt0}, {\tt a}, {\tt A}, \item [-d\ ]\ \\ Check double entries. \item [-f \ARG{key\_format}]\ \\ Generate keys according to \ARG{key\_format} \item [-F\ ]\ \\ Enable key generation with free key format. \item [-h\ ]\ \\ Print short help and exit. \item [-i \ARG{input\_file}]\ \\ Mark a file to be processed later. \item [-k\ ]\ \\ Make keys with the short format. \item [-K\ ]\ \\ Make keys with the long format. \item [-o \ARG{output\_file}]\ \\ Send the output to \ARG{output\_file}. \item [-q\ ]\ \\ Suppress warning messages. \item [-r \ARG{resource\_file}]\ \\ Read the resource file \ARG{resource\_file}. \item [-R\ ]\ \\ Load the default resource file now. \item [-s\ \ ]\ \\ Sort the result. \item [-S\ ]\ \\ Sort the result in reverse order. \item [-v\ \ ]\ \\ Turn on verbose messages about the actions performed. \item [-x \ARG{aux\_file}]\ \\ Extract those entries mentioned in \ARG{aux\_file}. \item [-X \ARG{regex}]\ \\ Extract entries matching \ARG{regex}. \end{FlatList} \Section{Libraries} \begin{tabular}{lp{.17\textwidth}} \Lib{check{\rm\_}y} & Check the value of the year.\\ \Lib{default} & All default settings.\\ \Lib{field} & Redefine field names.\\ \Lib{brace} & Use braces as delimiters.\\ \Lib{improve} & Apply improvements.\\ \Lib{iso2tex} & Translate ISO\,8859/1 characters.\\ \Lib{iso{\rm\_}def} & Define ISO\,8859/1 characters for formatting.\\ \Lib{month} & Introduce strings for month names.\\ \Lib{opt} & Remove OPT in field names.\\ \Lib{sort{\rm\_}fld} & Specify sort order for fields.\\ \Lib{tex{\rm\_}def} & Define \TeX{} macros for formatting.\\ \Lib{biblatex} & Capitalize fields known to bib\LaTeX.\\ \end{tabular} \Section{General} \begin{FlatList} \item [resource.search.path = \Arg{dir$_1$:dir$_2$\ldots }] \item [resource \Arg{file}] \item [bibtex.search.path = \Arg{dir$_1$:dir$_2$\ldots }] \item [bibtex.env.name = \Arg{ENV\_NAME}] \item [env.separator = \Arg{c}] \item [dir.file.separator = \Arg{c}] \item [print \Arg{message}] \item [quiet = \OnOff] \item [verbose = \OnOff] \item [crossref.limit = \Arg{n}] \end{FlatList} \columnbreak \Section{Reading and Printing} \begin{FlatList} \item [input \Arg{bib\_file}] \item [output.file = \Arg{file}] \item [pass.comments = \OnOff] \item [new.entry.type \Arg{type}] \item [print.align = \Num] \item [print.align.key = \Num] \item [print.align.preamble = \Num] \item [print.align.comment = \Num] \item [print.braces = \OnOff] \item [print.comma.at.end = \OnOff] \item [print.deleted.entries = \OnOff] \item [print.deleted.prefix = \Arg{prefix}] \item [print.indent = \Num] \item [print.line.length = \Num] \item [print.newline = \Num] \item [print.parentheses = \OnOff] \item [print.terminal.comma = \OnOff] \item [print.use.tab = \OnOff] \item [print.wide.equal = \OnOff] \item [suppress.initial.newline = \OnOff] \item [new.field.type \Arg{new=old}] \item [symbol.type = \ARG{type}]\ \\ upper, lower, cased \end{FlatList} \Section{Sorting} \begin{FlatList} \item [sort = \OnOff] \item [sort.cased = \OnOff] \item [sort.reverse = \OnOff] \item [sort.format = \Arg{format}] \item [sort.order \Arg{\ldots }] \item [sort.macros = \OnOff] \end{FlatList} \Section{Searching (Extraction)} \begin{FlatList} \item [tex.define \Arg{macro[arg]=text}] \item [extract.file \Arg{file}] \item [select \Arg{field$_1$\ldots field$_n$ "regex"}] \item [select \Arg{type$_1$\ldots type$_n$ }] \item [select.by.string \Arg{field$_1$\ldots field$_n$ "regex"}] \item [select.by.string.ignore \Arg{chars}] \item [select.case.sensitive = \OnOff] \item [select.fields = \Arg{field$_1$,field$_2$,\ldots }] \end{FlatList} \Section{Field Manipulation} \begin{FlatList} \item [add.field \Arg{field="value"}] \item [delete.field \Arg{field}] \item [rename.field \Arg{old=new}] \item [rename.field \Arg{old=new if field="pattern"}] \item [rewrite.rule \Arg{ pattern }]\ \\ delete all matching fields \item [rewrite.rule \Arg{ pattern \# replacement}]\ \\ rewrite all fields \item [rewrite.rule \Arg{f$_1$\ldots f$_n$ \# pattern \# replacement}]\ \\ rewrite some fields \item [rewrite.case.sensitive = \OnOff] \item [rewrite.limit = \Arg{n}] \end{FlatList} \Section{Checks} \begin{FlatList} \item [check.double = \OnOff] \item [check.do.delete = \OnOff] \item [check.rule \Arg{field \# pattern \# message}] \item [check.case.sensitive = \OnOff] \end{FlatList} \Section{Strings} \begin{FlatList} \item [macro.file \Arg{file}] \item [print.all.strings = \OnOff] \item [expand.macros = \OnOff] \item [expand.crossref = \OnOff] \end{FlatList} \NewPage \Section{\BibTeX1.0} \begin{FlatList} \item [apply.alias = \OnOff] \item [apply.include = \OnOff] \item [apply.modify = \OnOff] \item [key.make.alias = \OnOff] \end{FlatList} \Section{Counting} \begin{FlatList} \item [count.all = \OnOff] \item [count.used = \OnOff] \end{FlatList} \Section{Key Generation} \begin{FlatList} \item [preserve.keys = \OnOff] \item [preserve.key.case = \OnOff] \item [key.format = \Arg{format}]\ \\ special values: short, long, short.need, long.need, empty \item [key.generation = \OnOff] \item [default.key = \Arg{key}] \item [key.base = \ARG{base}]\ \\ values: upper, lower, digit \item [key.number.separator = \Arg{s}] \item [key.expand.macros = \OnOff] \item [fmt.name.title = \Arg{s}] \item [fmt.title.title = \Arg{s}] \item [fmt.name.name = \Arg{s}] \item [fmt.inter.name = \Arg{s}] \item [fmt.name.pre = \Arg{s}] \item [fmt.et.al = \Arg{s}] \item [fmt.word.separator = \Arg{s}] \item [new.format.type = \Arg{n="spec"}] \end{FlatList} \Section{Name Formatting Specification} Use {\it n}\/ letters. Use {\it m} name parts. Insert {\it pre}\/ before, {\it mid} between, and {\it post} after the words. Translate according to the s parameter ('+', '-', '*'). \begin{FlatList} \item [\%{\it s}{\it n}.{\it m}\/f{[{\it mid}][{\it pre}][{\it post}]}]\ \\ format first names. \item [\%{\it s}{\it n}.{\it m}\/v{[{\it mid}][{\it pre}][{\it post}]}]\ \\ format ``von'' part. \item [\%{\it s}{\it n}.{\it m}\/l{[{\it mid}][{\it pre}][{\it post}]}]\ \\ format last name. \item [\%{\it s}{\it n}.{\it m}\/j{[{\it mid}][{\it pre}][{\it post}]}]\ \\ format ``junior'' part. \end{FlatList} \Section{Format Specifications} \textbf{Pseudo fields:} \begin{FlatList} \item [\$key] \item [\$default.key] \item [\$sortkey] \item [\$source] \item [\$type] \item [@type] \item [\$day] \item [\$month] \item [\$mon] \item [\$year] \item [\$hour] \item [\$minute] \item [\$second] \item [\$user] \item [\$hostname] \end{FlatList} \textbf{Formatting Fields:} \begin{FlatList} \item [\%$\pm ${\it x}.{\it y}\/ n({\it field}\/)]\ \\ format {\it y}\/ characters of {\it x}\/ last names. \item [\%$\pm ${\it x}.{\it y}\/ N({\it field}\/)]\ \\ format {\it y}\/ characters of {\it x}\/ names. \item [\%$\pm ${\it x}.{\it y}\/ p({\it field}\/)]\ \\ format {\it x}\/ names according to the name format {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ d({\it field}\/)]\ \\ format at most {\it x}\/ digits of the {\it y}$^{th}$ number. \item [\%$\pm ${\it x}.{\it y}\/ D({\it field}\/)]\ \\ format {\it x}\/ digits of the {\it y}$^{th}$ number without truncation. \item [\%$\pm ${\it x}\/ s({\it field}\/)]\ \\ format {\it x}\/ string characters. \item [\%$\pm ${\it x}.{\it y}\/ t({\it field}\/)]\ \\ format {\it x}\/ sentence words of length {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ T({\it field}\/)]\ \\ format {\it x}\/ sentence words of length {\it y}. (Words ignored) \item [\%$\pm ${\it x}.{\it y}\/ w({\it field}\/)]\ \\ format {\it x}\/ words of length {\it y}. \item [\%$\pm ${\it x}\/ W({\it field}\/)]\ \\ format {\it x}\/ words of length {\it y}. (Words ignored) \item [\%$\pm ${\it x}.{\it y}\/ \#n({\it field}\/)]\ \\ test whether the number of names is between {\it x}\/ and {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ \#N({\it field}\/)]\ \\ test whether the number of names is between {\it x}\/ and {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ \#p({\it field}\/)]\ \\ test whether the number of names is between {\it x}\/ and {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ \#s({\it field}\/)]\ \\ test whether the number of characters is between {\it x}\/ and {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ \#t({\it field}\/)]\ \\ test whether the number of words is between {\it x}\/ and {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ \#T({\it field}\/)]\ \\ test whether the number of not ignored words is between {\it x}\/ and {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ \#w({\it field}\/)]\ \\ test whether the number of words is between {\it x}\/ and {\it y}. \item [\%$\pm ${\it x}.{\it y}\/ \#W({\it field}\/)]\ \\ test whether the number of not ignored words is between {\it x}\/ and {\it y}. \end{FlatList} \end{multicols} \vfill\vfill\vfill \begin{center}\rule{.8\textwidth}{.1pt}\\ Source repository and issue tracker at \link{https://github.com/ge-ne/bibtool} \end{center} \end{document} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Local Variables: % mode: latex % TeX-master: nil % End: BibTool/doc/Makefile0000644000175100017510000000666512646422602013256 0ustar genegene##*** Makefile **************************************************************** ## ## This file is part of BibTool. ## It is distributed under the GNU General Public License. ## See the file COPYING for details. ## ## (c) 1997-2016 Gerd Neugebauer ## ## Net: gene@gerd-neugebauer.de ## ##***************************************************************************** LATEX = latex PDFLATEX = pdflatex BIBTEX = bibtex MAKEINDEX = makeindex DIR_SEP = / .SUFFIXES: .tex .toc .dvi .pdf .aux .bbl .ind .idx $(SUFFIXES) .tex.pdf: $(PDFLATEX) $< .tex.dvi: $(LATEX) $< .tex.toc: $(PDFLATEX) $< .tex.idx: $(PDFLATEX) $< .tex.aux: $(PDFLATEX) $< .aux.bbl: $(BIBTEX) $* TARGETS = bibtool.pdf ref_card.pdf c_lib.pdf ##----------------------------------------------------------------------------- all: $(TARGETS) ##----------------------------------------------------------------------------- bibtool.dvi: config.tex bibtool.tex bibtool.bbl bibtool.ind $(LATEX) bibtool $(LATEX) bibtool bibtool.pdf: config.tex bibtool.tex bibtool.bbl bibtool.ind $(PDFLATEX) bibtool $(PDFLATEX) bibtool bibtool.ind ind index: bibtool.idx $(MAKEINDEX) -s bibtool.ist bibtool ##----------------------------------------------------------------------------- config.tex: ..$(DIR_SEP)version.c .$(DIR_SEP)make_version.pl .$(DIR_SEP)make_version.pl ..$(DIR_SEP)version.c > $*.tex ##----------------------------------------------------------------------------- ref_card.dvi: ref_card.tex config.tex $(LATEX) ref_card.tex ref_card.pdf: ref_card.tex config.tex $(PDFLATEX) ref_card.tex ##----------------------------------------------------------------------------- CDIR = ..$(DIR_SEP) HDIR = ..$(DIR_SEP)include$(DIR_SEP)bibtool$(DIR_SEP) CFILES = $(HDIR)bibtool.h \ $(HDIR)database.h \ $(CDIR)database.c \ $(HDIR)entry.h \ $(CDIR)entry.c \ $(HDIR)error.h \ $(CDIR)error.c \ $(HDIR)expand.h \ $(CDIR)expand.c \ $(HDIR)init.h \ $(CDIR)init.c \ $(HDIR)keynode.h \ $(HDIR)key.h \ $(CDIR)key.c \ $(HDIR)macros.h \ $(CDIR)macros.c \ $(HDIR)names.h \ $(CDIR)names.c \ $(HDIR)parse.h \ $(CDIR)parse.c \ $(HDIR)print.h \ $(CDIR)print.c \ $(HDIR)pxfile.h \ $(CDIR)pxfile.c \ $(HDIR)record.h \ $(CDIR)record.c \ $(HDIR)rewrite.h \ $(CDIR)rewrite.c \ $(HDIR)resource.h \ $(HDIR)rsc.h \ $(CDIR)rsc.c \ $(HDIR)s_parse.h \ $(CDIR)s_parse.c \ $(HDIR)stack.h \ $(CDIR)stack.c \ $(HDIR)sbuffer.h \ $(CDIR)sbuffer.c \ $(HDIR)symbols.h \ $(CDIR)symbols.c \ $(HDIR)tex_aux.h \ $(CDIR)tex_aux.c \ $(HDIR)tex_read.h \ $(CDIR)tex_read.c \ $(HDIR)type.h \ $(CDIR)type.c \ $(HDIR)version.h \ $(CDIR)version.c \ $(HDIR)wordlist.h \ $(CDIR)wordlist.c c_lib: $(LATEX) c_lib.tex $(MAKEINDEX) -s bibtool.ist c_lib $(LATEX) c_lib.tex c_lib.dvi: c_lib.tex c_main.tex c.tex config.tex $(LATEX) c_lib.tex $(MAKEINDEX) -s bibtool.ist c_lib $(LATEX) c_lib.tex c_lib.pdf: c_lib.tex c_main.tex c.tex config.tex $(PDFLATEX) c_lib.tex $(MAKEINDEX) -s bibtool.ist c_lib $(PDFLATEX) c_lib.tex c_main.tex: $(CDIR)main.c c_get.pl perl c_get.pl $(CDIR)main.c > $@ c.tex: $(CFILES) c_get.pl perl c_get.pl $(CFILES) > $@ ##----------------------------------------------------------------------------- clean: $(RM) *.bak *.BAK *~ *.log *.ilg *.blg *.toc *.out *.aux *.idx *.ind *.bbl veryclean: clean $(RM) c.tex c_main.tex config.tex distclean: veryclean $(RM) $(TARGETS) BibTool/doc/c_lib.tex0000644000175100017510000002570312646422540013403 0ustar genegene%%*** c_lib.tex *************************************************************** %% %% This file is part of BibTool. %% It is distributed under the Creative Commons Attribution-Share %% Alike 3.0 License. %% %% (c) 1997-2016 Gerd Neugebauer %% %% Net: gene@gerd-neugebauer.de %% %%----------------------------------------------------------------------------- %% Usage: latex c_lib %% makeindex -s bibtool.ist bibtool %% latex c_lib %%***************************************************************************** \NeedsTeXFormat{LaTeX2e} \documentclass[11pt,a4paper]{scrbook} \usepackage{array,shortvrb,makeidx} \usepackage[colorlinks=true, linkcolor=blue, citecolor=blue]{hyperref} \input{config} \hypersetup{pdftitle={BibTool C Programmers Manual}} \hypersetup{pdfauthor={Gerd Neugebauer}} \hypersetup{pdfsubject={Version \Version}} \makeindex \parindent=0pt \parskip=1ex \makeatletter \newcommand\ClassFont{\scriptsize\sf} \newcommand\File[2]{\section{The File \texttt{#1}}\label{sec:#2}} \newcommand\Header[2]{\section{The Header File \texttt{#1}}\label{sec:#2}} \newcommand\Module[2]{\section{The Module \texttt{#1}}\label{sec:#2}} \newcommand\Fct[1]{\textbf{\large #1}} \newcommand\Mac[1]{\textbf{\large #1}} \newcommand\Var[1]{\textbf{#1}} \newcommand\Type[1]{\textbf{#1}} \newenvironment{Function}[2]{% \begin{description}\item[\texttt{#1()}]\index{#2()|tt}\ \hfill{\ClassFont Function}\\% }{\end{description}} \newenvironment{Macro}[2]{% \begin{description}\item[\texttt{#1()}]\index{#2()|sf}\ \hfill{\ClassFont Macro}\\% }{\end{description}} \newenvironment{Constant}[2]{% \begin{description}\item[\texttt{#1}]\index{#2|sf}\ \hfill{\ClassFont Macro}\\% }{\end{description}} \newenvironment{Variable}[2]{% \begin{description}\item[\texttt{#1}]\index{#2|tt}\ \hfill{\ClassFont Variable}\\% }{\end{description}} \newenvironment{Result}{% \begin{description}\item[\textmd{Returns:}] }{\end{description}} \newenvironment{Arguments}[1]{\begingroup\tt\tabcolsep=0pt \begin{tabular*}{.925\textwidth}{ll@{\extracolsep{\fill}}>{\it\small}p{.55\textwidth}} #1% }{\end{tabular*}\endgroup\par} \newenvironment{Typedef}[2]{\begin{description}% \item[#1]\ \hfill{\ClassFont Type}\\}{} \newcommand\STRUCT[1]{\par \texttt{typedef struct}% \textbf{\ #1 } \texttt{\char123}\par \begingroup\tt\tabcolsep=0pt\rule{1em}{0pt}% \begin{tabular*}{.9\textwidth}% {ll@{\extracolsep{\fill}}>{\it\small}p{.55\textwidth}}% } \newcommand\EndSTRUCT[1]{\end{tabular*}\endgroup\par \texttt{\char125} #1; \end{description} } \newcommand\Member[1]{\textbf{#1}} \makeatother \MakeShortVerb{|} \newcommand\Ccomment[1]{\hfill\parbox[t]{.5\textwidth}{\it/* #1\hfill*/}} \newcommand\BibTool{{\sc Bib\hskip-.1em\-% \mbox{T\hskip-.15emo\hskip-.05emo\hskip-.05eml}}} \newcommand\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} \makeatletter%>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \def\ps@headings{\let\@mkboth\markboth \def\@oddfoot{}\def\@evenfoot{} \def\@evenhead{\vbox{\vss\hbox to \textwidth{\rm\thepage \hss {\scriptsize\sc\ \leftmark}}\kern 1.5mm\hrule depth 0.2 true pt}} \def\@oddhead{\vbox{\vss\hbox to \textwidth{\rm{\scriptsize\sc \rightmark\ } \hss \thepage}\kern 1.5mm\hrule depth 0.2 true pt}} \def\chaptermark##1{\markboth {\ifnum \c@secnumdepth>\m@ne \thechapter. \ \fi ##1}{}} \def\sectionmark##1{\markright {\ifnum \c@secnumdepth >\z@ \thesection. \ \fi ##1}}} \pagestyle{headings} \addtolength{\headheight}{2pt} \makeatother \newfont\cminch{cminch} \ifx\chaptername\relax\else \renewcommand\chaptername{\cminch} \renewcommand\appendixname{\cminch} \fi \newcommand\rfill[1]{\leaders\hrule height #1\hfill} \newcommand\Link[2]{\texttt{#2}} \newcommand\email[1]{\texttt{#1}} \newcommand\INCOMPLETE{\begin{center} \unitlength=1mm\framebox(80,10)\textsf{To be completed.} \end{center}} \begin{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \thispagestyle{empty} \null\vfill {\begin{center} \rule{\textwidth}{5pt}% \bigskip\par \hbox to \textwidth{\cminch \hss B\hss I\hss B\hss T\hss O\hss O\hss L\hss} \medskip\par\normalsize \mbox{}\rfill{5pt}\ A Tool to Manipulate \BibTeX\ Files\ \rfill{5pt}\null %\medskip\par\normalsize Version \Version \vfill {\Huge\bf C Programmers Manual}\vfill {\LARGE\it $\cal G$\kern-.1emerd $\cal N$\kern-.2emeugebauer} \vfill\vfill \begin{minipage}{.8\textwidth}\small \begin{center} \bf Abstract \end{center} \BibTool{} provides a library of useful C functions to manipulate \BibTeX{} files. This library has been used to implement the \BibTool{} program. This document describes This library and allows you to write C programs dealing with \BibTeX{} files. \end{minipage}\vfill\vfill \textsf{\small --- This documentation is still in a rudimentary form and needs additional efforts. ---} \end{center}} %------------------------------------------------------------------------------ \newpage \noindent \begin{minipage}{\textwidth}\parskip=1ex This file is part of \BibTool{} Version \Version \medskip Copyright {\copyright}\Year{} Gerd Neugebauer \medskip \BibTool{} 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 1, or (at your option) any later version. \BibTool{} 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 documentation; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. \end{minipage} \vfill\par\noindent Gerd Neugebauer\\ Im Lerchelsb\"ohl 5\\ 64521 Gro\ss-Gerau (Germany)\smallskip\par\noindent WWW: \Link{http://www.gerd-neugebauer.de/}{http://www.gerd-neugebauer.de/} \smallskip\par\noindent Net: \email{gene@gerd-neugebauer.de} %------------------------------------------------------------------------------ \tableofcontents \chapter{Introduction} The \BibTool{} C library provides functions to deal with \BibTeX{} files. These functions are described in this document. Thus it should be fairly easy to write new C program which handle \BibTeX{} files. The reader is assumed to be familiar with \BibTeX{} files. this documentation will not repeat an introduction into \BibTeX. This documentation can not only be used to write new C programs dealing with \BibTeX{} files but also to understand \BibTool---The Program which serves as one example for using the \BibTool C library. In any case it is essential to understand some of the underlying concepts. Thus it is vital to read some sections very carefully. Especially the section The \BibTool{} program uses the \BibTool{} C library. Well, in fact it is the other way round. Historically the \BibTool{} program was first and then the library has been extracted from it. Nevertheless the \BibTool{} program can serve as an example how the \BibTool{} C libary can be used. \input c_main \chapter{The \BibTool{} C Library} \input c \chapter{Creating and Using the \BibTool{} C Library} \section{Creating the \BibTool{} C Library} Creating the \BibTool{} library should not be too hard. Mainly make \BibTool{} in the main directory according to the instructions given there. As a side effect various object files are created. These object files---except the one for main.c---have to be put into the library. For UNIX this is prepared in the makefile. Usually an invocation of make should be enough: \begin{verbatim} make libbib.a \end{verbatim} This invocation of make is in fact the same as the following two commands: \begin{verbatim} ar r libbib.a $OFILES ranlib libbib.a \end{verbatim} Here |$OFILES| denotes the list of object files as described above. On some systems no ranlib program is present and needed. In this case the second command can be omitted. For other operating systems I simply do not know how things work there. I would be grateful to receive descriptions what to do there. \section{Using the \BibTool{} C Library} %First of all you need to include the appropriate header file which %provides all If you have written a program which uses the \BibTool{} C Library you have to include the library into the linking list. In addition the directory where the library can be found has to be specified. On UNIX this can be done with the compiler switches |-l| and |-L| respectively. Thus consider you have a program named |mybib.c| and you have created the object file |mybib.o| for it. The linking step can be performed with the following command: \begin{verbatim} cc mybib.o -L$DIR -lbib -o mybib \end{verbatim} Here |$DIR| denotes the path containing the file |libbib.a|. This path can be omitted if the library has been installed in a ``standard'' place like |/usr/lib|. \chapter{Coding Standards} Several tools are used for the development of \BibTool. Mostly they are home grown---maybe they will be replaced by some wider used tools some day. Among those tools are indentation routines for Emacs to format the comments contained in the source. There is also a Lisp function to generate the function prototypes contained in the header files and sometimes in the C files as well. And finally there is a Program to extract the documentation from the source files and generate a printable manual. All those support programs rely on standards for coding. Some of those standards have been develped independantly but should be used for consistency. In the following sections these coding standards are described. \section{K\&R-C vs. ANSI-C} \BibTool{} tries hard to be portable to wide variety of C systems. Thus it can not be assumed that an ANSI C compiler is at hand. As a consequence the function heads are written in the old style which is also tolerated by ANSI compliant compilers. This means that the argument types are given after the argument list. Here it is essential that the arguments type declarations are given in the same order as the arguments of the function. Each type variable must have a new type declaration in a line by it's own. This feature is used by the program which extracts the function prototypes. Those function heads are use to generate function prototypes which can be understood by ANSI-C compilers as well as by of K\&R compilers. This is achieved by the od trick to introduce a macro which expands to nothing on the old compilers and to its aregument on ANSI compilers. This macro is defined appropriately according to the existence of the macro \verb|__STDC__| which should indicate an ANSI compliant compiler. %\section{Indentation} \printindex \end{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Local Variables: % mode: latex % TeX-master: nil % End: BibTool/doc/c_get.pl0000755000175100017510000001617312646460774013246 0ustar genegene#!/usr/bin/perl #------------------------------------------------------------------------------ # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 1997-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #***************************************************************************** foreach $_ (@ARGV) { print STDERR "$_\n"; &analyze_file($_); } sub analyze_file { local ($file) = @_; local (%purpose,$name,%function,%macro,%variable,$state); open(FD,$file) || return; $file =~ s/_/\\_/go; $file =~ s/^\.\.\///o; $file =~ s/^include\///o; $_ = $file; s/[^.a-zA-Z0-9]//go; if ( /\.c$/ ) { print "\n\\Module{$file}{$_}\n\n"; } elsif ( /\.h$/ ) { print "\n\\Header{$file}{$_}\n\n"; } else { print "\n\\File{$file}{$_}\n\n"; } $state = 0; while () { if (/^\*\*/o) { if (/^\*\* Function:[ ]*([a-zA-Z0-9_]+)/o) { $name = $1; $name =~ s/_/\\_/go; $source{$name} = $file; $type{$name} = 0; $function{$name} = 1 } elsif (/^\*\* Macro:[ ]*([a-zA-Z0-9_]+)/o) { $name = $1; $name =~ s/_/\\_/go; $source{$name} = $file; $type{$name} = 10; $macro{$name} = 1; } elsif (/^\*\* Constant:[ ]*([a-zA-Z0-9_]+)/o) { $name = $1; $name =~ s/_/\\_/go; $source{$name} = $file; $type{$name} = 11; $macro{$name} = 1; } elsif (/^\*\* Typedef:[ ]*([a-zA-Z0-9_]+)/o) { $name = $1; $name =~ s/_/\\_/go; $source{$name} = $file; $type{$name} = 22; } elsif (/^\*\* Type:[ ]*([%* a-zA-Z0-9_]+)/o) { $head{$name} = "$1 \\Mac{$name}"; } elsif (/^\*\* Variable:[ ]*([a-zA-Z0-9_]+)/o) { $name = $1; $name =~ s/_/\\_/go; $source{$name} = $file; $type{$name} = 1; $variable{$name} = 1; } elsif (/^\*\*[ ]*Description:[ ]*([a-zA-Z0-9_]*)/o) { print $1."\n" if $1 ne ''; $state = 9; } elsif ($name eq '' && $state == 0 ) { } elsif (/^\*\* Arguments:/o) { $state = 2; @a = (); } elsif (/^\*\* Returns:[ ]*(.*)/o) { $returns{$name} = ' '.$1; $state = 3; } elsif (/^\*\* Purpose:[ ]*(.*)/o) { $_ = $1; s/_/\\_/go; $purpose{$name} = ' '.$_; $state = 1; } elsif (/^\*\* Example:[ ]*(.*)/o) { $_ = $1; s/_/\\_/go; $example{$name} = ' '.$_; $state = 5; } elsif ( /^\*\*[-*_]/o ) { $state = 0; if ( $type{$name} == 10 ) { $_ = $name; s/\\_//go; if ( $head{$name} eq '' ) { $n = "\\Mac{$name}"; } else { $n = $head{$name}; } print "\\begin{Macro}{$n}{$_}\n \\begin{Arguments}"; foreach $a (@a) { print "\n & \\Var{$a} & $arg{$a}\\\\"; } print "\n \\end{Arguments}%\n"; print "$purpose{$name}\n"; print " \\begin{Result}\n$returns{$name}\n \\end{Result}\n" if ($returns{$name} ne ''); print "\\end{Macro}\n"; $name = ''; } elsif ( $type{$name} == 11 ) { $_ = $name; s/\\_//go; if ( $head{$name} eq '' ) { $n = "\\Mac{$name}"; } else { $n = $head{$name}; } print "\\begin{Constant}{$n}{$_}\n"; print "\n \\begin{Arguments}$arg{$name}\n \\end{Arguments}%\n" if ($arg{$name} ne ''); print "$purpose{$name}\n"; print "\\end{Constant}\n"; $name = ''; } elsif ( $type{$name} == 1 ) { $_ = $name; s/\\_//go; if ( $head{$name} eq '' ) { $n = "\\Mac{$name}"; } else { $n = $head{$name}; } print "\\begin{Variable}{$n}{$_}\n"; print "$purpose{$name}\n"; print "\\end{Variable}\n"; $name = ''; } elsif ( $type{$name} == 22 ) { $_ = $name; s/\\_//go; if ( $head{$name} eq '' ) { $n = "\\Type{$name}"; } else { $n = $head{$name}; } print "\\begin{Typedef}{$n}{$_}\n"; print "$purpose{$name}\n"; $name = ''; $state = 22; } } elsif ( $state == 9 && /^\*\*[ ]*(.*)/o ) { print $1."\n"; } elsif ( $state == 1 && /^\*\*[ ]*(.*)/o ) { $purpose{$name} = $purpose{$name}."\n ".$1; } elsif ( $state == 2 && /^\*\* (.*)/o ) { $arg{$lastarg} = $arg{$lastarg}."\n".$1; } elsif ( $state == 2 && /^\*\*[ ]+([a-zA-Z0-9_]+)[ ]*(.*)/o ) { $arg{$1} = $2; $lastarg = $1; push (@a,($1)); } elsif ( $state == 3 && /^\*\*[ ]*(.*)/o ) { $returns{$name} = $returns{$name}."\n ".$1; } } elsif ( /^([a-zA-Z_][^(]*[^a-zA-Z0-9_(])([a-zA-Z0-9_]*)/o && $state == 0 ) { $_ = "$1\\Fct{$2}"; if ( /^static/ ) { undef $purpose{$name}; } else { s/_/\\_/go; $head{$name} = $_; $proto{$name} = ''; $state = 11; } } elsif ( $state == 11 && /^[ ]+([^;]*;)/o ) { $_ = $1; s/register //o; s/[ ]+/ /go; s/_ARG\((.*)\)/$1/o; if ( /^(.*\([^a-zA-Z0-9_]*)([a-zA-Z0-9_]+)(\)\(.*\);)$/o ) { $_ = "$1\\ \t&\\Var{$2}$3 \t&$arg{$2}"; } else { s/([a-zA-Z0-9_]+)(\[[0-9a-zA-Z_]*\])?;/\\ \t&\\Var{$1}$2;\t&$arg{$1}/o; } s/_/\\_/go; if ($proto{$name} eq '') { $proto{$name} = "\n ".$_; } else { $proto{$name} = $proto{$name}."\\\\\n ".$_; } } elsif ( $state == 22 ) { if ( /^[ ]*typedef[ ]*struct[ ]*([a-zA-Z_0-9]+|)/o ) { print " \\STRUCT{$1}\n"; $NL = ''; } elsif (/^[ ]*}[ ]*(.*[a-zA-Z])[ ]*;/o) { $x = ''; foreach $_ (split(/,[ ]*/,$1)) { $x = $x . ', ' if ( $x ne ''); $x = $x . "\\Type{$_}"; } print "\n \\EndSTRUCT{$x}\n\\end{Typedef}\n"; $state = 0; } elsif ( /^[ {]*([a-zA-Z_][^(]*[^a-zA-Z0-9_(])([a-zA-Z0-9_]+);[ ]*\/\*[ ]*(.*)\*\//o ) { $_ = $2; $t = $1; $c = $3; s/_/\\_/go; print "$NL $t\\ \t&\\Member{$_};\t& $c"; $NL = "\\\\\n"; } elsif ( /^[ {]*([a-zA-Z_][^(]*[^a-zA-Z0-9_(])([a-zA-Z0-9_]+);/o ) { $_ = $2; $t = $1; s/_/\\_/; print "$NL $t\\ \t&\\Member{$_};\t& "; $NL = "\\\\\n"; } elsif ( /^[ ]*\/\*[ ]*(.*)\*\//o ) { print "\n\t\t\t$1"; } else { print $_; } } elsif ( /^{/o && $name ne '' ) { $name = ''; $state = 0; } } foreach $_ (sort(keys %function)) { if ( $_ ne '' && $head{$_} ne '' ) { print "\\begin{Function}{$head{$_}}{$_}"; print "\n \\begin{Arguments}$proto{$_}\n \\end{Arguments}%\n" if ($proto{$_} ne ''); print "$purpose{$_}\n"; print " \\begin{Result}\n$returns{$_}\n \\end{Result}\n"; print "\\end{Function}\n"; } } close(FD); } #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/doc/make_version.pl0000755000175100017510000000361612646425656014645 0ustar genegene#!/usr/bin/perl -w ##***************************************************************************** ## make_version.pl ##***************************************************************************** ## Author: Gerd Neugebauer ##============================================================================= =head1 NAME make_version.pl - Create the content for config.tex =head1 SYNOPSIS make_version.pl [-v|--verbose] make_version.pl [-h|-help] =head1 DESCRIPTION =head1 OPTIONS =head1 AUTHOR Gerd Neugebauer =back =cut use strict; #------------------------------------------------------------------------------ # Function: usage # Arguments: none # Returns: nothing # Description: Print the POD of this file to stderr. # sub usage { use Pod::Text; Pod::Text->new()->parse_from_filehandle(new FileHandle($0,'r'),\*STDERR); } #------------------------------------------------------------------------------ # Variable: $verbose # Description: Indicator for verbosity # my $verbose = 0; my $LIBDIR = '/usr/local/lib/BibTool'; use Getopt::Long; GetOptions("h|help" => \&usage, "v|verbose" => \$verbose, ); my $version = undef; @_ = localtime; my $year = 1900 + $_[5]; while(<>) { $version = $1 if m/bibtool_version *= *"([0-9.]*)/; $year = $1 if m/bibtool_year *= *"([0-9]*)/; } die "*** Missing version\n" if not defined $version; print <<__EOF__; %%******************************************************** %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-$year Gerd Neugebauer %% %% Net: gene\@gerd-neugebauer.de %% %%******************************************************** \\newcommand\\LIBDIR{$LIBDIR} \\newcommand\\Year{$year} \\newcommand\\Version{$version} __EOF__ #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/AutoConf/makefile.in0000644000175100017510000004005312646461260014664 0ustar genegene# *** makefile **************************************************************** # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 1996-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # ***************************************************************************** # Look also in the file include/bibtool/config.h for additional # configuration parameters. # Read the file INSTALL for explanation. # ============================================================================= # This is the generic makefile for BibTool. # Especially it can be used on Unix systems and as a basis for # systems not directly mentioned in the distribution. # ============================================================================= # Configuration Section # ============================================================================= # prefix = @prefix@ exec_prefix = @exec_prefix@ # ------------------------------------------------------- # Prefix to be prepended to all installation directories. # Thus it is possible to install in a different location # as the final location. This seems useful for building # RPMs on Linux. INSTALLPREFIX = # ------------------------------------------------------- # Destination directory for make install # This is usually a directory where public executables # are installed. BINDIR = @bindir@ # ------------------------------------------------------- # Destination directory for make install.man # This is usually a directory where public man pages # are installed. # Additionally name the section of the man pages to use. # This should be 1 (user commands), l (local), or n (new) # MANDIR = @mandir@ MANSECT = 1 # ------------------------------------------------------- # Destination directory for make install.lib # This is usually a directory where public shared files # are installed plus a final BibTool. # LIBDIR = @libdir@/BibTool #------------------------------------------------------- # Destination directory for make install.include # This is usually a directory where public include files # are installed plus a final `bibtool'. # Note: The include files may contain system specific # code and may not be shared amoung architectures. # INCLUDEDIR = @includedir@/bibtool # ------------------------------------------------------- # Name the C compiler # CC = @CC@ # ------------------------------------------------------- # CFLAGS are the flags for the C compiler. # For debugging it should be -g. # For final version you can try to activate # the optimizer with -O or -O2 or whatever # BEWARE: Some C compiler produce erroneous code if the # optimizer is turned on. # CFLAGS = @CFLAGS@ # CFLAGS = -O # GNU C # CFLAGS = -g -Wall # CFLAGS = -g -Wall -pedantic -Wpointer-arith -Wshadow -Wcast-align ##------------------------------------------------------- ## C_INCLUDE are the flags for the C compiler pointing it ## to the location of the header files. Usually this ## does not need any modifications. ## C_INCLUDE = -Iinclude # ------------------------------------------------------- # EXT is the optional extension of the final executable. # Various operating systems have their own ideas about # that. # EXT = # ------------------------------------------------------- # Extension of object files # OBJ = .o # ------------------------------------------------------- # Name some programs # # ------------------------------------------------------- # MV is a command to move certain files maybe to other # directories or drives. Only plain files are moved. # MV = mv # ------------------------------------------------------- # RM is a command to remove certain files. It should not # be confused when trying to remove non-existent files. # Only plain files are removed this way. # RM = rm -rf # ------------------------------------------------------- # MAKEDEPEND is a program to find dependencies for # .c and .h files. # Not present on MS-DOS, Atari, Amiga, Next MAKEDEPEND = makedepend # MAKEDPEND = gcc -MM # ------------------------------------------------------- # INSTALL is a program to properly install some files. # Maybe cp should also do this job (on UNIX) INSTALL = @INSTALL@ # ------------------------------------------------------- # INSTALL_DATA is a command to install some data files. # INSTALL_DATA = @INSTALL_DATA@ # ------------------------------------------------------- # INSTALL_DIR is a command to create a directory if not # already existent. If your install does not support the # -d option you can try to use mkdir instead. INSTALL_DIR = ./mkdirchain # ------------------------------------------------------- # The ranlib program or : for nothing. # RANLIB = @RANLIB@ # ------------------------------------------------------- # The ar program invocation to add files to the archive. # AR = ar r # ------------------------------------------------------- # PERL is the complete path to an existing perl executable. # Perl 4.* and Perl 5.* are both ok. # PERL = @PERL@ # ------------------------------------------------------- # LINT is a program to check the C source for problems. # LINT = lint # ------------------------------------------------------- # CXREF is a C cross reference program. # CXREF = cxref # ------------------------------------------------------- # Defines to support (non-ANSI) C compilers. # For Solaris 2 you may have to define HAVE_STRING_H # For some versions of Cygwin you may have to define # STD_HEADERS. # For ANSI C compilers they should be empty. # Mostly needed for the GNU regex library. # Include # -DHAVE_STRING_H if your C compiler has string.h # (e.g. on Solaris 2) # Maybe you have to enlarge the # include search path. # -DREGEX_MALLOC if you have NO alloca() library # function # -DHAVE_ALLOCA_H if you need alloca.h for alloca() # -DSTDC_HEADERS if gcc reports conflicting types # for malloc (on Linux?) # NON_ANSI_DEFS = @DEFS@ # ------------------------------------------------------- # GNU Regular Expression Library support. # First of all the (sub)directory containing the # necessary files (excluding trailing slash). # # This directory is contained in the BibTool distribution. # I have tried newer versions of this library without # positive results. (Try it if you don't believe me:-) # REGEX_DIR = regex-0.12 # REGEX_DEF = -DREGEX -I$(REGEX_DIR) -I.. REGEX = regex$(OBJ) # ------------------------------------------------------- # Kpathsea Library support. # This library provides means to specify a search path # with recursive search in subdirectories. # The library is NOT contained in the BibTool distribution. # This routines are expected to work with Kpathsea-2.6 or # above. # # See the file INSTALL for details. # # Kpathsea is not known to work yet on anything else but # Unix platforms. # This item is purely experimental. # Maybe you are better off not trying it! # # The value of KPATHSEA_DIR is the directory containing # the distribution of kpathsea. I.e. the directory # containing the subdirectory kpathsea. # The value of KPATHSEA is the name of the kpathsea library. # if kpathsea should not be used then it has to be empty. # The value of KPATHSEA_DEF are the additional flags for the # C compiler. It should arrange things that the macro # KPATHSEA is defined and the directory beneath kpathsea # is in the include search path. KPATHSEA_DIR = @kpathsea_dir@ KPATHSEA = @kpathsea_lib@ KPATHSEA_STATIC = @kpathsea_lib_static@ KPATHSEA_DEF = @kpathsea_def@ # ------------------------------------------------------- # Default search paths # The values are NULL or a string containing a colon # separated list of directories. # DON'T FORGET THE CURRENT DIRECTORY! # # The character ENV_SEP separates the directories in # environment search paths. # BIBINPUTS_DEFAULT = NULL BIBTOOL_DEFAULT = \".:$(LIBDIR)\" ENV_SEP = \":\" # ------------------------------------------------------- # Declare the file naming conventions. # FILE_TYPES contains optionally a macro definition # determining the file naming conventions. # -DMS-DOS denotes MSDOG-like file names. (Also for Atari) # -DAMIGA denotes the Amiga file names. # The default (empty) are UN*X-like file names. # # DIR_SEP is the directory-file separator. FILE_TYPES = DIR_SEP = / # ============================================================================= # End of Configuration Section # ============================================================================= MAKEFILE = makefile SHELL = /bin/sh RSC_DEF = -DRSC_BIBINPUTS_DEFAULT=$(BIBINPUTS_DEFAULT) \ -DRSC_BIBTOOL_DEFAULT=$(BIBTOOL_DEFAULT) \ -DENV_SEP=$(ENV_SEP) DONT_LINK = -c LINK_TO = -o STANDALONE = -DSTANDALONE C_FLAGS = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) $(C_INCLUDE) $(FILE_TYPES) LD_FLAGS = $(LDFLAGS) CFILES = main.c \ $(CLIBFILES) CLIBFILES = crossref.c \ database.c \ entry.c \ error.c \ expand.c \ init.c \ key.c \ macros.c \ names.c \ parse.c \ print.c \ pxfile.c \ record.c \ rewrite.c \ rsc.c \ s_parse.c \ symbols.c \ stack.c \ sbuffer.c \ tex_aux.c \ tex_read.c \ type.c \ version.c \ wordlist.c HPATH = include${DIR_SEP}bibtool${DIR_SEP} HFILES = config.h \ ${HPATH}crossref.h \ ${HPATH}database.h \ ${HPATH}bibtool.h \ ${HPATH}config.h \ ${HPATH}entry.h \ ${HPATH}error.h \ ${HPATH}expand.h \ ${HPATH}general.h \ ${HPATH}init.h \ ${HPATH}key.h \ ${HPATH}keynode.h \ ${HPATH}macros.h \ ${HPATH}names.h \ ${HPATH}parse.h \ ${HPATH}print.h \ ${HPATH}pxfile.h \ ${HPATH}regex.h \ ${HPATH}record.h \ ${HPATH}resource.h \ ${HPATH}rewrite.h \ ${HPATH}rsc.h \ ${HPATH}s_parse.h \ ${HPATH}sbuffer.h \ ${HPATH}stack.h \ ${HPATH}symbols.h \ ${HPATH}tex_aux.h \ ${HPATH}tex_read.h \ ${HPATH}type.h \ ${HPATH}version.h \ ${HPATH}wordlist.h OFILES = main$(OBJ) \ $(OLIBFILES) OLIBFILES = crossref$(OBJ) \ database$(OBJ) \ entry$(OBJ) \ error$(OBJ) \ expand$(OBJ) \ init$(OBJ) \ key$(OBJ) \ macros$(OBJ) \ names$(OBJ) \ parse$(OBJ) \ print$(OBJ) \ pxfile$(OBJ) \ record$(OBJ) \ rewrite$(OBJ) \ rsc$(OBJ) \ s_parse$(OBJ) \ symbols$(OBJ) \ stack$(OBJ) \ sbuffer$(OBJ) \ tex_aux$(OBJ) \ tex_read$(OBJ) \ type$(OBJ) \ version$(OBJ) \ wordlist$(OBJ) DOCFILES = doc$(DIR_SEP)bibtool.1 \ doc$(DIR_SEP)bibtool.tex \ doc$(DIR_SEP)bibtool.bib \ doc$(DIR_SEP)bibtool.ist \ doc$(DIR_SEP)bibtool-doc.sty \ doc$(DIR_SEP)ref_card.tex \ doc$(DIR_SEP)Makefile \ doc$(DIR_SEP)config.tex \ doc$(DIR_SEP)c_main.tex \ doc$(DIR_SEP)c_lib.tex \ doc$(DIR_SEP)c.tex \ doc$(DIR_SEP)c_get.pl \ doc$(DIR_SEP)make_version.pl LIBFILES = lib$(DIR_SEP)biblatex.rsc \ lib$(DIR_SEP)braces.rsc \ lib$(DIR_SEP)check_y.rsc \ lib$(DIR_SEP)default.rsc \ lib$(DIR_SEP)field.rsc \ lib$(DIR_SEP)improve.rsc \ lib$(DIR_SEP)iso2tex.rsc \ lib$(DIR_SEP)month.rsc \ lib$(DIR_SEP)opt.rsc \ lib$(DIR_SEP)sort_fld.rsc \ lib$(DIR_SEP)tex_def.rsc PROGFILES = Perl$(DIR_SEP)bibtool.pl \ Tcl$(DIR_SEP)bibtool.tcl ETCFILES = README.md \ install.tex \ COPYING \ Changes.tex \ makefile.unx \ makefile.dos \ makefile.ata \ makefile.ami \ ToDo \ THANKS \ pxfile.man \ sbuffer.man \ $(MSDOS_targets) \ $(PROGFILES) DISTFILES = $(ETCFILES) \ $(CFILES) \ $(HFILES) \ $(LIBFILES) \ $(DOCFILES) \ $(REGEX_DIR) # ----------------------------------------------------------------------------- # The main target # ----------------------------------------------------------------------------- default all: bibtool$(EXT) bibtool$(EXT): $(OFILES) $(REGEX) $(KPATHSEA_STATIC) $(CC) $(LD_FLAGS) $(C_FLAGS) $(LINK_TO) $@ $(OFILES) $(REGEX) $(KPATHSEA) $(KPATHSEA_STATIC) tex_read$(EXT): tex_read.c $(CC) $(LD_FLAGS) $(C_FLAGS) $(STANDALONE) tex_read.c $(LINK_TO) tex_read$(EXT) tex_aux$(OBJ): tex_aux.c $(CC) $(C_FLAGS) $(REGEX_DEF) $(DONT_LINK) tex_aux.c -o tex_aux$(OBJ) main$(OBJ): main.c $(CC) $(C_FLAGS) $(REGEX_DEF) $(KPATHSEA_DEF) $(DONT_LINK) main.c init$(OBJ): init.c $(CC) $(C_FLAGS) $(KPATHSEA_DEF) $(DONT_LINK) init.c parse$(OBJ): parse.c $(CC) $(C_FLAGS) $(KPATHSEA_DEF) $(DONT_LINK) parse.c -o parse$(OBJ) rewrite$(OBJ): rewrite.c $(CC) $(C_FLAGS) $(REGEX_DEF) $(DONT_LINK) rewrite.c -o rewrite$(OBJ) rsc$(OBJ): rsc.c $(CC) $(C_FLAGS) $(RSC_DEF) $(DONT_LINK) rsc.c -o rsc$(OBJ) .c$(OBJ): $(CC) $(C_FLAGS) $(DONT_LINK) -c $< -o $@ # __________________________________________________________________ # Include the makefile into the dependencies to force updates # when the makefile is modified. $(OFILES): $(MAKEFILE) # __________________________________________________________________ # Targets from the GNU Regular Expression Library. regex$(OBJ): $(REGEX_DIR)$(DIR_SEP)regex.c $(MAKEFILE) $(CC) $(C_FLAGS) -I$(REGEX_DIR) -I.. $(NON_ANSI_DEFS) $(REGEX_DIR)$(DIR_SEP)regex.c $(DONT_LINK) -o $@ bibtcl: cd BibTcl && $(MAKE) $(MFLAGS) # ----------------------------------------------------------------------------- # General development targets # ----------------------------------------------------------------------------- CLEAN_TARGETS = *$(OBJ) xref *.bak core #* *~ clean mostlyclean: -cd doc && $(MAKE) $(MFLAGS) clean -cd test && $(MAKE) $(MFLAGS) clean -cd BibTcl && $(MAKE) $(MFLAGS) clean -$(RM) $(CLEAN_TARGETS) veryclean distclean realclean extraclean: clean -cd doc && $(MAKE) $(MFLAGS) distclean -cd test && $(MAKE) $(MFLAGS) distclean -$(RM) bibtool config.cache config.status config.log makefile doc: d-o-c d-o-c: cd doc; $(MAKE) $(MFLAGS) DIR_SEP=$(DIR_SEP) info: test check: Test Test: (cd test; $(MAKE)) libbib.a: $(OLIBFILES) $(AR) $@ $(OLIBFILES) regex.o $(RANLIB) $@ depend: -$(MAKEDEPEND) -fmakefile -DMAKEDEPEND -Iinclude $(CFILES) install: install.bin install.lib install.bin install-exec: bibtool$(EXT) -$(INSTALL_DIR) $(INSTALLPREFIX)$(BINDIR) $(INSTALL) bibtool$(EXT) $(INSTALLPREFIX)$(BINDIR) INSTALL_LIB_FILES = lib$(DIR_SEP)*.* install.lib install-data: -$(INSTALL_DIR) $(INSTALLPREFIX)$(LIBDIR) for lib in $(INSTALL_LIB_FILES); do \ $(INSTALL_DATA) $$lib $(INSTALLPREFIX)$(LIBDIR); \ done INSTALL_INCLUDE_FILES = $(HFILES) install.include install-include: -$(INSTALL_DIR) $(INSTALLPREFIX)$(INCLUDEDIR) for inc in $(INSTALL_INCLUDE_FILES); do \ $(INSTALL_DATA) $$inc $(INSTALLPREFIX)$(INCLUDEDIR); \ done install.man install-man: -$(INSTALL_DIR) $(INSTALLPREFIX)$(MANDIR)$(DIR_SEP)man$(MANSECT) $(INSTALL) doc$(DIR_SEP)bibtool.1 \ $(INSTALLPREFIX)$(MANDIR)$(DIR_SEP)man$(MANSECT)$(DIR_SEP)bibtool.$(MANSECT) uninstall: uninstall.bin uninstall.lib uninstall.bin uninstall-exec: -$(RM) $(INSTALLPREFIX)$(BINDIR)$(DIR_SEP)bibtool$(EXT) uninstall.lib uninstall-data: -$(RM) $(INSTALLPREFIX)$(LIBDIR) uninstall.include uninstall-include: -$(RM) $(INSTALLPREFIX)$(INCLUDEDIR) uninstall.man uninstall-man: -$(RM) $(INSTALLPREFIX)$(MANDIR)$(DIR_SEP)man$(MANSECT)$(DIR_SEP)bibtool.$(MANSECT) status: @echo $(LIBDIR) # ============================================================================= # DO NOT DELETE THIS LINE -- make depend depends on it. BibTool/AutoConf/reconfig.h.in0000644000175100017510000000447712646460035015142 0ustar genegene/*** reconfig.h *************************************************************** ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2016 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ******************************************************************************/ /*----------------------------------------------------------------------------- ** Define if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /*----------------------------------------------------------------------------- ** Define if you have alloca, as a function or macro. */ #undef HAVE_ALLOCA #ifndef HAVE_ALLOCA #define REGEX_MALLOC #endif /*----------------------------------------------------------------------------- ** Define if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H /*----------------------------------------------------------------------------- ** Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. ** This function is required for alloca.c support on those systems. */ #undef CRAY_STACKSEG_END /*----------------------------------------------------------------------------- ** If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION BibTool/BibTcl/bibtcl.bib0000644000175100017510000000206312254326671014115 0ustar genegene%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% bibtcl.bib %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @Book{ ousterhout:tcl, author = {John K. Ousterhout}, title = {Tcl and the Tk Toolkit}, publisher = {Addison Wesley Publishing Company}, year = {1994}, address = {Reading, Mass.}, optedition = {}, optmonth = {}, optnote = {}, optannote = {} } @Book{ welch:practical, author = {Brent B. Welch}, title = {Practical Programming in Tcl and Tk}, publisher = {Prentice Hall PTR}, year = {1995}, address = {Upper Saddle River, New Jersey}, optedition = {}, optmonth = {}, optnote = {}, optannote = {} } @Manual{ neugebauer:bibtool, author = {Gerd Neugebauer}, title = {{BibTool} -- A Tool to Manipulate {\BibTeX} Files}, edition = {2.41}, year = {1997} } @STRING{bibtool = {{BibTool}} } @Manual{ neugebauer:bibtcl, title = bibtool # { -- Tcl Programmers Manual}, crossref = {neugebauer:bibtool}, remark = {Distributed with BibTool} } BibTool/BibTcl/bibtcl.ltx0000644000175100017510000001300112254326706014161 0ustar genegene%%***************************************************************************** %% bibtcl.ltx %%***************************************************************************** %% Author: Gerd Neugebauer %%----------------------------------------------------------------------------- \newif\ifAfour \Afourtrue \ifx\documentclass\undefined \ifAfour \documentstyle[11pt,dina4,makeidx]{book} \else \documentstyle[11pt,makeidx]{book} \fi \newcommand\LaTeXTeX{(\kern-.15emL\kern-.36em\raise.3ex\hbox{\sc a}\kern-.3em)\kern-.15em\TeX}% \else \documentclass[11pt]{book} \usepackage{makeidx} \ifAfour \makeatletter \input{dina4.sty} \DeclareRobustCommand{\LaTeXTeX}{(\kern-.15emL\kern-.36em% {\sbox\z@ T% \vbox to\ht0{\hbox{$\m@th$% \csname S@\f@size\endcsname \fontsize\sf@size\z@ \math@fontsfalse\selectfont A}% \vss}% }\kern-.2em)% \kern-.15em% \TeX} \makeatother \fi \DeclareFontShape{OT1}{cmss}{m}{it}{<-> ssub * cmss/m/sl}{} \fi \makeatletter%>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \def\ps@headings{\let\@mkboth\markboth \def\@oddfoot{}\def\@evenfoot{} \def\@evenhead{\vbox{\vss\hbox to \textwidth{\rm\thepage \hss {\scriptsize\sc\ \leftmark}}\kern 1.5mm\hrule depth 0.2 true pt}} \def\@oddhead{\vbox{\vss\hbox to \textwidth{\rm{\scriptsize\sc \rightmark\ } \hss \thepage}\kern 1.5mm\hrule depth 0.2 true pt}} \def\chaptermark##1{\markboth {\ifnum \c@secnumdepth>\m@ne \thechapter. \ \fi ##1}{}} \def\sectionmark##1{\markright {\ifnum \c@secnumdepth >\z@ \thesection. \ \fi ##1}}} \pagestyle{headings} \addtolength{\headheight}{2pt} \newcommand\opt[1]{{\tt-#1}\index{#1@{\tt-#1}}} \newcommand\sh{\smallskip\par\hspace*{2em}\@ifnextchar[{\sh@}{\sh@@}} \def\sh@[#1]#2{{\tt bibtool -#1 {\it #2}}\index{#1@{\tt-#1}} \smallskip\par\noindent\ignorespaces} \def\sh@@#1{{\tt bibtool {\it #1}} \smallskip\par\noindent\ignorespaces} \newcommand\rsc[1]{{\sf #1}\index{#1@{\sf #1}}} \newcommand\RSc[2]{\smallskip\par\hspace*{2em}{\sf #1 #2}\index{#1@{\sf #1}} \smallskip\par\noindent\ignorespaces} \newcommand\RSC[2]{\RSc{#1}{= \(\{\)#2\(\}\)}} \newcommand\Rsc[2]{\RSc{#1}{= #2}} \newcommand\env[1]{{\tt #1}\index{#1@{\tt #1}}} \makeatother%<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \newcommand\BS{$\backslash$} \newcommand\BibTool{{\sc Bib\hskip-.1em\-% \mbox{T\hskip-.15emo\hskip-.05emo\hskip-.05eml}}} \newcommand\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} \newfont\cminch{cminch} \ifx\chaptername\relax\else \renewcommand\chaptername{\cminch} \renewcommand\appendixname{\cminch} \fi \newcommand\rfill[1]{\leaders\hrule height #1\hfill} \newcommand\INCOMPLETE{\begin{center} \unitlength=1mm\framebox(80,10){\sf To be completed.} \end{center}} \makeindex \input version \begin{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \thispagestyle{empty} \null\vfill {\begin{center} \rule{\textwidth}{5pt}% \bigskip\par \hbox to \textwidth{\cminch \hss B\hss I\hss B\hss T\hss O\hss O\hss L\hss} \medskip\par\normalsize \mbox{}\rfill{5pt}\ A Tool to Manipulate \BibTeX\ Files\ \rfill{5pt}\null %\medskip\par\normalsize Version \Version \vfill {\Huge\bf Tcl Programmers Manual}\vfill {\LARGE\it $\cal G$\kern-.1emerd $\cal N$\kern-.2emeugebauer} \vfill\vfill \begin{minipage}{.8\textwidth}\small \begin{center} \bf Abstract \end{center} \BibTool{} provides a library of useful C functions to manipulate \BibTeX{} files. This library has been used to implement new primitives for Tcl which utilize these functions. Thus it is easy to write tools to manipulate \BibTeX{} files or graphical interfaces to them. \end{minipage}\vfill\vfill {\small\sf --- This documentation is still in a rudimentary form and needs additional efforts. ---} \end{center}} %------------------------------------------------------------------------------ \newpage \noindent \begin{minipage}{\textwidth}\parskip=1ex This file is part of \BibTool{} Version \Version \medskip Copyright {\copyright}\Year{} Gerd Neugebauer \medskip \BibTool{} 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 1, or (at your option) any later version. \BibTool{} 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 documentation; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. \end{minipage} \vfill\par\noindent Gerd Neugebauer\\ Mainzer Str.\ 8\\ 56321 Rhens (Germany)\smallskip\par\noindent WWW: {\tt http://www.uni-koblenz.de/\~{}gerd}\smallskip\par\noindent Net: {\tt gerd@informatik.uni-koblenz.de}\\ \phantom{Net:} {\scriptsize\tt gerd@imn.th-leipzig.de}\\ \phantom{Net:} {\tiny\tt gerd@intellektik.informatik.th-darmstadt.de} %------------------------------------------------------------------------------ \tableofcontents \chapter{The Tcl Module} \input bibtcl.tex \printindex \bibliographystyle{alpha} \bibliography{bibtcl} \end{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Local Variables: % mode: latex % TeX-master: nil % End: BibTool/BibTcl/bibtcl.tex0000644000175100017510000021070212550700706014154 0ustar genegene%%***************************************************************************** %% bibtcl.tex %%***************************************************************************** %% Author: Gerd Neugebauer %%----------------------------------------------------------------------------- %% %% To generate the printed documentation run LaTeX on the %% driver file bibtcl.ltx. %% %%----------------------------------------------------------------------------- \newcommand\code[1]{{\tt #1}} \newcommand\meta[1]{{\it #1\/}} \newcommand\file[1]{{\sf #1}} \newcommand\TclSummaryLabel[1]{{\bf #1\hss}} \newcommand\TclSummary[3]{\TclSummaryOO{bibtool #1 #2}{#3}\index{bibtool!#1}} \newcommand\TclSummaryOO[2]{\begin{list}{}{% \parskip=0pt \parsep=0pt \topsep=0pt \rightmargin=2em \advance\leftmargin \rightmargin \let\makelabel\TclSummaryLabel} \item[#1] \ \par #2 \end{list}} \section{Introduction} The following description assumes that you are familiar with Tcl \cite{ousterhout:tcl,welch:practical}. Thus it does not repeat any introductory material on this language. You are referred to one of the books or the material to be found on the Web. If you are not familiar enough with Tcl you are strongly encouraged to read an introductory text since there are some subtle points in Tcl which have to be understood. Otherwise the language is not usable. The \BibTool{} library is made available for the Tcl programming language in the form of a dynamic loadable library. To use this library it is usually sufficient to source the file \file{bibtool.tcl} which is created during the installation of the library (see section~\ref{sec:installation}) and which can be found in the same directory where the machine dependent library resides---even though this file is not architecture dependent. Thus the first instruction to use the library in a Tcl program is \begin{verbatim} source bibtool.tcl \end{verbatim} The file \file{bibtool.tcl} contains the information where the libraries can be found. It tries to find and load the appropriate dynamic library for the operating system and version it is running on. If you encounter problems like missing libraries then just reinstall the \BibTool{} library on this architecture into the same directory. This will create a new subdirectory containing the missing library. \section{Functional vs.\ Object-Oriented Reading} During the development of the \BibTool{} library an interesting question occurred. In principle there are two ways of thinking present even in plain Tcl/Tk, namely a functional/pro\-ce\-du\-ral and an object oriented point of view. The object oriented point of view can be seen mainly in Tk where the widgets act like objects. In Tcl most things have only a procedural flavor. The question arose which paradigm should be supported. The first consideration was to use the procedural paradigm since this would require only a single new Tcl command to be implemented. This means the simplicity argument won. When lots of subcommands of this single command \code{bibtool} had already been implemented the issue was reconsidered. It turned out that only one single wrapper function had to be written in C to provide the object oriented point of view. Thus for many subcommands of \code{bibtool}---namely those dealing with databases or entries---there are two alternative notations available. Consider for example the following situation. the Tcl variables \code{entry1} and \code{entry2} contain references to single entries (we will see later how we can come to this situation). Then the equality of the entries (in the sense of pointers to the same internal data structure) can be checked with \begin{verbatim} bibtool equal $entry1 $entry2 \end{verbatim} This returns \code{1} upon success and \code{0} upon failure. In the object oriented paradigm we have to provide a method of a entry which decides whether or not it is identical to another entry. This can be written as \begin{verbatim} $entry1 equal $entry2 \end{verbatim} Another example is concerned with the access to a entry in a database. Suppose we have a reference to a database stored in the Tcl variable \code{db} and we have already loaded some \BibTeX{} files into this database. Then we can get a reference to the first entry---storing it in the Tcl variable \code{entry}---with the following command: \begin{verbatim} set rec [bibtool first $db] \end{verbatim}%$ If we consider \code{\$db} as an object then we can use the method \code{first} to get the first entry: \begin{verbatim} set rec [$db first] \end{verbatim}%$ Thus we have available both paradigms in this library. This effect is achieved by using handles to objects. These handles have the prefix \code{=BibTcl=}. For each object created a command is defined which is an alias to the appropriate \code{bibtool} subcommand. As long as the user does not try to define commands with this prefix everything works fine. \section{Databases} \code{bibtool} is designed to handle several databases simultaneously. To distinguish the different databases they get assigned a handle---which is a unique identifier---when they are created. This handle has to be used to refer to a database later on. Thus it is preferable to store it in Tcl variable. The handle can also be seen as an object in an object oriented context. The database class provides a fixed set of methods for this object. Instead of using an object oriented notation we have decided to use a more procedural approach. But you can have your own model in mind when you read the code. One consequence of the use of handles is that \BibTool{} can determine which kind of object is addressed. In case of an invalid object an appropriate error is raised. This can occur for instance if a database handle is used after the database has been deleted, or if an arbitrary string is given as handle which does not correspond to an object in \BibTool. The first step to work with a database is the creation. This can be done with the command \code{bibtool new}. This command returns a handle for a new database which should be stored in a Tcl variable for later user: \begin{verbatim} set db [bibtool new] \end{verbatim}% This database is empty. If you want to load some files into this database you can give the filenames as arguments to \code{bibtool new}. Any number of \BibTeX{} files can be given this way: \begin{verbatim} set db [bibtool new a.bib b.bib c.bib] \end{verbatim}% Since \BibTool{} is rather noisy by default it might be preferable to reduce the verbosity before loading a database. This can be done by utilizing \BibTool{} resources as in the following command: \begin{verbatim} bibtool quiet=on verbose=off \end{verbatim}% Details on the use of \BibTool{} resources can be found in section~\ref{sec:tcl-resources} on page~\pageref{sec:tcl-resources}. But the files can not be loaded at creation time only but also later on. This is done with the command \code{bibtool read} as shown in the following example: \begin{verbatim} bibtool read $db c.bib d.bib \end{verbatim}%$ \code{bibtool read} needs the next argument to be a handle for a database. Any following arguments are taken to be file names which are loaded into the given database. Upon success the databse handle is returned. If one of the files does not exist, can not be read, or another error occurrs then this command issues a Tcl error. You can use \code{catch} to avoid a termination of Tcl and implement an error recovery scheme: \begin{verbatim} foreach file {c.bib d.bib} { if {[catch {bibtool read $db $file} message]} { puts stderr "*** $message" } } \end{verbatim}%$ The next important operation on a database is the writing operation. The command \code{bibtool write} writes the named database into the given file. Again an error is raised if this writing can not be performed. This is most probably caused by the inability to open the file. \begin{verbatim} set file abc.bib if {[catch {bibtool write $db $file} message]} { puts stderr "*** $message" } \end{verbatim}%$ Usually the database is written to the file deleting its previous contents. Sometimes it can be desirable to append the database to an existing file. For this purpose the flag \code{-append} can be used: \begin{verbatim} if {[catch {bibtool write $db $file -append} message]} { puts stderr "*** $message" } \end{verbatim}%$ There is one special case of a file name. If the file name is the empty string then the output is written to the standard output stream. The final operation on a database is its deletion. This can be done with the command \code{bibtool delete}. This command takes as argument a single \BibTool{} object and performs the delete operation for it. Now we are interested in a database object only. Thus the object is a database handle. \begin{verbatim} bibtool delete $db \end{verbatim}%$ This command deletes the database \code{\$db}. Any reference to it or its contents might lead to a Tcl error. This deletion does not remove the file on the disk but only frees the handle. With the means given in this section we can already write a useful tool. If we want to write a Tcl program which normalizes a \BibTeX{} file then this can be done with the following piece of code: \begin{verbatim} bibtool quiet=on verbose=off bibtool write [bibtool new [lindex $argv 0]] [lindex $argv 1] \end{verbatim}% This Tcl program reads the \BibTeX{} file given as command line argument one and writes it to the file given as the second argument. No error detection is performed. To implement error recovery and the generalization to several input files is left to the reader. In fact this is a special case of the main loop of \BibTool. The same effect could be achieved with the following command line invocation of \BibTool: \begin{verbatim} bibtool -- quiet=on -- verbose=off infile -o outfile \end{verbatim} where \code{infile} and \code{outfile} are the names of the input and output files respectively. Next we want to have access to the entries in a database. For this purpose two methods are provided which return a handle for the first or last entry in a given database respectively. These handles should be stored in Tcl variables for later use: \begin{verbatim} set rec1 [$db first] set rec2 [$db last] \end{verbatim} If the database is empty then no handle is created and the empty string is returned. Next we can try to find a certain entry in the database by speifying its key. This can be accomplished with the \code{find} method: \begin{verbatim} set rec [$db find $key] \end{verbatim} If no appropriate entry is found then the empty string is returned. If you are finished with the database you should release it. This is done with the \code{delete} method: \begin{verbatim} $db delete \end{verbatim}%$ This command tries to free the memory occupied by the database\footnote{Currently a part of the memory is not really freed but kept internally to be reused by the next database.}. This operation invalidates the handle the the database and any handles to entries therein. This means that any access with such handles leads to a Tcl error. One method is present which can be used to check a handle: \begin{verbatim} $db valid \end{verbatim}%$ This command returns \code{1} if the database is a valid database or entry handle. Here is one place where it is preferable to use the procedural writing: \begin{verbatim} bibtool valid $db \end{verbatim}%$ This works for any string argument \code{\$db} not only those which have been valid \BibTool{} handles previously. \begin{table}[tp] \TclSummaryOO{\meta{DB} count \meta{varname}}{} \TclSummary{count}{\meta{DB} \meta{varname}}{Count the nunber of entries of each type and store the result in the Tcl array \meta{varname}. The old contents of this varaible is lost.} \TclSummaryOO{\meta{DB} delete}{} \TclSummary{delete}{\meta{DB}}{delete a database such that no further operations are possible on them. Cf. \code{bibtool delete} for entries.} \TclSummaryOO{\meta{DB} find \meta{KEY}}{} \TclSummary{find}{\meta{DB} \meta{KEY}}{Return a new entry handle which corresponds to the first normal entry in the database \meta{DB} which has the key \meta{KEY}. If none is found then the empty string is returned.} \TclSummaryOO{\meta{DB} first}{} \TclSummary{first}{\meta{DB}}{Return a new entry handle which corresponds to the first normal entry in the database \meta{DB}. If the database is empty then the empty string is returned.} \TclSummaryOO{\meta{DB} last}{} \TclSummary{last}{\meta{DB}}{Return a new entry handle which corresponds to the last normal entry in the database \meta{DB}. If the database is empty then the empty string is returned.} \caption{Summary of database operations}\label{fig:tcl-database} \rule{\textwidth}{.1pt} \end{table} \begin{table}[tp] \TclSummary{new}{}{create a new database and return a handle to it.} \TclSummaryOO{\meta{DB} preamble}{} \TclSummary{preamble}{\meta{DB}}{Return the preamble of the database \meta{DB}.} \TclSummaryOO{\meta{DB} read \meta{?FILE \ldots?}}{} \TclSummary{read}{\meta{DB} \meta{?FILE \ldots?}}{read the contents of the \BibTeX{} file \meta{FILE} into the database \meta{DB}.} \TclSummaryOO{\meta{DB} entry \meta{TYPE}}{} \TclSummary{entry}{\meta{DB} \meta{TYPE}}{Create a new entry in the database \meta{DB} with the type \meta{TYPE}.} \TclSummaryOO{\meta{DB} sort \meta{?-generate?} \meta{?-reverse?}}{} \TclSummary{sort}{\meta{DB} \meta{?-generate?} \meta{?-reverse?}}{sort the database \meta{DB} according to the sort keys. If \meta{-generate} is specified then the sort keys are generated first according to the resource \rsc{sort.format}. The sort order is ascending or descending depending on the resource \rsc{sort.reverse}. If the argument \meta{-reverse} is given then this order is reversed again.} \TclSummary{sort.format}{=\meta{FORMAT}}{} \TclSummaryOO{\meta{DB} valid}{} \TclSummary{valid}{\meta{DB}}{check whether the database handle \meta{DB} is still valid. A database handle is invalidated by the \code{delete} operation.} \TclSummaryOO{\meta{DB} write \meta{FILE} \meta{?-append?}}{} \TclSummary{write}{\meta{DB} \meta{FILE} \meta{?-append?}}{write the contents of the database \meta{DB} into the file \meta{FILE}. If the option \meta{-append} is given then the contents is appended to the file. If the file is the empty string then the output is written to stdout.} \addtocounter{table}{-1}% \caption{Summary of database operations (continued)}\label{fig:tcl-database2} \rule{\textwidth}{.1pt} \end{table} A summary of the commands discussed in this section can be found in Table~\ref{fig:tcl-database}. \section{Entries and Fields} Any \BibTool{} database consists of a set of entries. Currently there are three types of entries which are treated differently. The normal entry consists of a set of fields which have names and values. The following example illustrates such a normal entry:\label{example:bibtool} \begin{verbatim} @Manual{ neugebauer:bibtool, author = {Gerd Neugebauer}, title = {{BibTool} -- A Tool to Manipulate {\BibTeX} Files}, edition = {2.41}, year = {1997} } \end{verbatim} Currently there are two kinds of special entries, namely \code{@preamble} and \code{@string} entries. These types of entries will be discussed later and we will focus for the moment on normal entries. To navigate through the database the methods \code{forward} and \code{backward} are provided. These commands take a entry handle as argument and modify it such that it references the next or previous entry respectively. Upon success the entry handle is returned. If there is no next or previous entry then the handle is released and the empty string is returned. \begin{verbatim} if {[$entry forward]==""} {puts {At end.}} if {[$entry backward]==""} {puts {At beginning.}} \end{verbatim} With these methods we are able to write down a loop which visits all normal entries. We show the loop starting from the first element and approaching to the last one. As an application we count the number of entries in the database: \begin{verbatim} set count 0 for { set rec [$db first] } \ { $entry != "" } \ { set rec [$entry forward] }\ { incr count 1 } \end{verbatim}%$ Like for database handles we might be interested to get rid of a entry handle. For this purpose the method \code{delete} is also provided for entries. The deletion of a entry handle invalidates this handle. It does not alter the database in any way. Thus after the following piece of code the database has not been changed. \begin{verbatim} set rec [$db first] $entry delete \end{verbatim} \label{bibtool:remove}% If you want to delete a database entry you can use the method \code{bibtool remove}. This takes as argument a single entry and removes it from the database. Additionally the handle is invalidated. Thus it can not be used any more. Consider the problem of looping through all entries and deleting some of them. For this purpose we want to assume that we have a boolean function \code{has\_to\_be\_deleted} which decides whether the entry given as argument has to be deleted. Then the loop can be implemented as follows: \begin{verbatim} for {set rec [$db first]} \ {[bibtool $entry valid]} \ {set rec $next} { set next [$entry dup] $next forward if {[has_to_be_deleted $entry]} {$entry remove} } \end{verbatim}%$ In this example we see several new things. First of all we see the method \code{bibtool remove} in action. Next we see the method \code{bibtool valid} which can not only be used to check valid database handles but also valid entry handles. It works absolutely analogously and is no surprise. The new method which might be surprising is the \code{bibtool dup}. This method creates a new entry handle which points to the same entry as the handle given as argument. This is necessary since manipulations on the first handle can now be performed safely because they do not effect the new handle---except when the entry is deleted. Let us have a look at \code{bibtool dup} with another example. Let us assume that the Tcl variable \code{entry} contains a valid entry handle for the database \code{db}. The following piece of code creates a Tcl variable \code{new} which contains the same entry handle as \code{entry}: \begin{verbatim} set new $entry $entry forward \end{verbatim} The \code{bibtool forward} operation on \code{entry} modifies \code{new} as well. Thus \code{new} either points to the next entry of the initial one or it is invalidated if no such entry exists. In contrast the following piece of code creates a new handle and stores it in the Tcl variable \code{new}. \begin{verbatim} set new [$entry dup] $entry forward \end{verbatim} In this example \code{new} is not effected by the \code{bibtool forward} operation on \code{entry}. Even if there is no next entry and \code{entry} is invalidated then \code{new} still references the initial entry. We have to come back to \code{bibtool valid} to complete the picture. Often it is interesting to know in advance whether the next or previous entry exists without duplicating a entry handle and moving just to avoid to invalidate a entry handle. For this purpose an additional argument can be used. If this optional argument to \code{bibtool valid} after the entry handle is \code{-next} or \code{-previous} then the existence of the next resp.\ previous entry is checked in addition to the validity of the entry handle itself. Thus the following fragment checks whether there are at least two entries in the database \code{\$db}. This is done by positioning a entry at the beginning of the database and checking the validity of this entry and the next entry: \begin{verbatim} set rec [$db first] if { [bibtool valid $entry] && [bibtool valid $entry -previous] } { puts {At least two entries.} } \end{verbatim}%$ Since we have the possibility to clone a entry handle with \code{bibtool dup} or allocate new ones with \code{bibtool first} or \code{bibtool last} we need method to compare two entry handles to see whether they point to the same entry. This function is called \code{bibtool equal}. This function takes two arguments and returns \code{1} if they are valid and point to the same entry. If they are valid and point to different entries then \code{0} is returned. If either one is invalid then an error is raised. Suppose we have a valid entry handle stored in the Tcl variable \code{entry} for which a next entry exists. We execute the following piece of code: \begin{verbatim} set new $entry $entry forward if {[$entry equal $new]} {print yes} \end{verbatim} The last line will always produce the answer \code{yes}. This is due to the fact that the Tcl variables \code{entry} and \code{new} contain in fact the same entry handle. Whereas the following piece of code will never produce \code{yes} since here two independent entry handles are involved which represent successive entries in the database. \begin{verbatim} set new [$entry dup] $entry forward if {[$entry equal $new]} {print yes} \end{verbatim} As an convenient alias the method \code{bibtool ==} is provided as an alias for the method \code{bibtool equal}. Thus you can write \begin{verbatim} if {[$entry == $new]} {print yes} \end{verbatim} This line will have the same effect as the last line in the example above. But beware not to forget the outer brackets. This subtle point is illustrated in the following example: \begin{verbatim} set new [$entry dup] if {[$entry == $new]} {print yes} else {print no} if { $entry == $new } {print yes} else {print no} \end{verbatim}%$ According to the explanations given earlier it is not surprising that the first conditional prints \code{yes} since both entry handles point to the same entry in the database. But they are in fact two different handles since \code{new} is derived from \code{entry} with the \code{bibtool dup} method. Thus the textual representation of the handles is different. These textual representations are compared in the second conditional and turn out not to be equal. As a consequence \code{no} is printed. This slight distinction might lead to confusion. If you have problems of this kind try to use \code{equal} instead of \code{==}. On the other hand the \code{==} notation is very intuitive and you just have to take care of the context in which it is evaluated by Tcl. \begin{table}[tp] \TclSummaryOO{\meta{ENTRY} backward}{} \TclSummary{backward}{\meta{ENTRY}}{Makes \meta{ENTRY} reference to the predecessor of its current value. Return \meta{ENTRY} upon success. If none is present then delete the entry handle and return the empty string.} \TclSummaryOO{\meta{ENTRY} delete}{} \TclSummary{delete}{\meta{ENTRY}}{Deletes the entry handle \meta{ENTRY}. This does not mean that the entry itself is modified. Only the reference to it can not be used any more.} \TclSummaryOO{\meta{ENTRY} dup}{} \TclSummary{dup}{\meta{ENTRY}}{Create a new entry handle pointing to the same entry as the entry handle \meta{ENTRY}.} \TclSummaryOO{\meta{ENTRY$_1$} equal \meta{ENTRY$_2$}}{} \TclSummary{equal}{\meta{ENTRY$_1$} \meta{ENTRY$_2$}}{compares the two entries. Returns 1 if they point to the same physical entry.} \TclSummaryOO{\meta{ENTRY$_1$} == \meta{ENTRY$_2$}}{} \TclSummary{==}{\meta{ENTRY$_1$} \meta{ENTRY$_2$}}{the same as \code{equal}.} \TclSummaryOO{\meta{ENTRY} fields}{} \TclSummary{fields}{\meta{ENTRY}}{Return a list of normal fields in the entry.} \TclSummaryOO{\meta{ENTRY} remove}{} \TclSummary{remove}{\meta{ENTRY}}{Remove the entry from its database. The handle is invalidated. The entry ceases to exist.} \TclSummaryOO{\meta{ENTRY} valid \meta{?-next\(\mid\)-previous?}}{} \TclSummary{valid}{\meta{ENTRY} \meta{?-next\(\mid\)-previous?}}{ check whether the entry handle \meta{ENTRY} is still valid. If the optional argument \meta{-previous} or \meta{-next} is given then it is also checked whether the previous or next entry exists. \code{1} is returned when all tests are successful. Otherwise \code{0} is returned.} \caption{Summary of entry operations}\label{fig:tcl-entry} \rule{\textwidth}{.1pt} \end{table} \section{Entry Fields}\label{sec:fields} As a database consists of a set of entries, any entry consists of a set of fields. The fields are determined by their name. Each name is unique within a entry. In addition to the name any field has a value. \BibTeX{} itself does not impose much restrictions on the allowed fields---except that they have some minor syntactic restrictions. Especially there is only one field which is treated special. This is the \code{crossref} field which is used for inheritance. Before we come to this point we want to present a method how to check for existing and not existing fields. The method \code{bibtool fields} of a entry returns the list of all fields defined in a entry. For instance we can reconsider the \BibTeX{} entry on page~\pageref{example:bibtool}. Suppose the Tcl variable \code{entry} contains a handle pointing to this entry then \begin{verbatim} fields $entry \end{verbatim}%$ \noindent would return the following list of fields: \begin{verbatim} author title edition year \end{verbatim} In addition to the normal fields which are stored directly in the entry, some information can be acessed as if it was stored in a field. Those pseudo-fields will be discussed later. To check for the existence or non-existence of a field one would could extract the list of fields and use the Tcl command \code{lsearch}. To avoid the overhead of constructing the intermediate list the method \code{bibtool missing} is provided. \begin{verbatim} $entry missing publisher \end{verbatim}%$ This invocation returns \code{1} if there is no field with the name |publisher| in the entry \code{entry}. Otherwise \code{0} is returned. As always an error is raised if \code{entry} does not contain a valid entry handle. Now we come to the access methods for field values. We need a way to retrieve the value and a method to modify the value. The first approach to retrieve a value is using the method \code{bibtool get}. It takes a entry handle and a field name and returns the contents of the field as a string. Let us consider the following example: \begin{verbatim} @String{ BibTool = {{BibTool}} } @Manual{ neugebauer:bibtcl, title = BibTool # { -- Tcl Programmers Manual}, crossref = {neugebauer:bibtool}, remark = {Distributed with BibTool} } \end{verbatim} If we want to get the value of the \code{remark} field we can use the following method: \begin{verbatim} $entry get remark \end{verbatim}%$ This command returns the contents of the remark field as string. Thus the result is the Tcl string \begin{verbatim} Distributed with BibTool \end{verbatim} The example has been chosen to illustrate some other points as well. In this example a \BibTeX{} macro \code{BibTool} is defined which contains the \BibTool{} logo protected from case changes in \BibTeX. This macro is used in the title field with the concatenation operator \code{\#}. Now we want to get the value of the title field: \begin{verbatim} $entry get title \end{verbatim}%$ This command yields as a result the string representation of the title field. For this purpose all macros are replaced by their values and the resultings strings are concatenated. Thus the result is \begin{verbatim} {BibTool} -- Tcl Programmers Manual \end{verbatim} Note that the outer double quotes or braces are not contained in the result but inner braces or doulbe quotes are. This is due to the fact that the result is a Tcl string which does not need additional delimiters. What would have happend if the macro \code{BibTool} would not have been defined? In this case the result of the macro expansion is the empty string. This empty string would have been concatenated with the rest yielding the result \begin{verbatim} -- Tcl Programmers Manual \end{verbatim} Sometimes it is undesirable to get the expanded version of the value. For instance if you want to take advantage of the \BibTeX{} macro feature and manipulate things yourself. For this purpose the optional flag \code{-noexpand} can be used. If this flag is given the result is a Tcl list consisting of strings which contain the components of the value. In this case the delimiters (\verb|{}| or \verb|""|) are part of the elements to distinguish the string constants from macros. Thus the command \begin{verbatim} $entry get title -noexpand \end{verbatim}%$ \noindent leads to a Tcl list with the following two elements: \begin{verbatim} BibTool { -- Tcl Programmers Manual} \end{verbatim} Next we have to consider the case that we are asking for a field which does not exist in the entry considered. For instance we might ask for the author field: \begin{verbatim} $entry get author \end{verbatim}%$ Since the entry does not contain an \code{author} field we get the empty string as the result. \BibTeX{} has the feature to use the \code{crossref} field for inheritance. If a field is missing in a entry but it has a \code{crossref} field then the field is sought in the entry whose key is the value of the \code{crossref} field as well. This behaviour can be triggered with the optional flag \code{-all} of the method \code{bibtool get}: \begin{verbatim} $entry get author -all \end{verbatim}%$ In our example the entry \code{neugebauer:bibtool} would be considered in this case. If we assume that this entry---as given on page~\pageref{example:bibtool}---is also present in the database then the result is the string \begin{verbatim} Gerd Neugebauer \end{verbatim} In addition to the normal fields some pseudo-fields can be queried. These pseudo-fields give access to information not really stored as a field but present for a entry, a database, or as a global value in other form. One such a pseudo-field is the citation key. This citation key can be referenced as \code{\$key}. Thus the citation key can be retrieved with the following Tcl construct: \begin{verbatim} set key [$entry get {$key}] \end{verbatim} Since the \code{\$} is a special character for Tcl it has to be protected to be not evaluated by Tcl. For our example the entry as given on page~\pageref{example:bibtool} this command will set the Tcl variable \code{key} to the value \begin{verbatim} neugebauer:bibtcl \end{verbatim} \begin{table}[t] \begin{center}\doublerulesep=.4pt \begin{tabular}{lp{.6\textwidth}}\hline\hline {\it pseudo field name}\rule[-1.5ex]{0pt}{4ex} & {\it meaning}\\\hline\rule{0pt}{3ex}% \code{\$key} & The citation key. \\ \code{\$sortkey} & The sort key, i.e.\ the string used for sorting entries.\\ \code{\$source} & The file the entry is read from or the empty string. \\ \code{\$type} & The type of the entry. \\ \code{\$default.key} & The value of the resource \code{default.key}. This string is used as a key if the key specification failes completely.\\ \code{\$fmt.et.al} & The value of the resource \code{fmt.et.al}. This string is used to abbreviate unnamed additional authors.\\ \code{\$fmt.name.pre} & The value of the resource \code{fmt.name.pre}. This string is inserted between the first name and the last name.\\ \code{\$fmt.inter.name} & The value of the resource \code{fmt.inter.name}. This string is inserted between several last names of one person.\\ \code{\$fmt.name.name} & The value of the resource \code{fmt.name.name}. This string is inserted between two names.\\ \code{\$fmt.name.title} & The value of the resource \code{fmt.name.title} This string is inserted between name and title.\\ \code{\$fmt.title.title}& The value of the resource \code{fmt.title.title}. This string is inserted between different words of the title.\\ \code{\$fmt.key.number} & The value of the resource \code{fmt.key.number}. This string is inserted between the generated key and the disambiguating number.\\[1ex] \hline\hline \end{tabular} \caption{Some pseudo fields}\label{tab:pseudo-fields} \end{center} \end{table} Table~\ref{tab:pseudo-fields} contains a list of pseudo fields. There are more pseudo fields which can be found in the \BibTool{} documentation. But the additional pseudo fields can not be considered really important in the context of Tcl. Now we come to the opposite operation. We want to set the value of a field to a given string. For this purpose the method \code{bibtool set} is provided. This method takes a field name and a string or a list of components and sets the value accordingly. Since Tcl does not distinguish between a list and a string the second case has to be marked with the flag \code{-concat}. The effect of this operation is that the field has the given value afterwards. If the field did not exist already then this field is added to the entry. Let us consider an example. The simplest desire is to set the value of a field to new string. Suppose we want to change the value of the remark field then this can be done as follows: \begin{verbatim} $entry set remark {Distributed as part of BibTool} \end{verbatim}%$ Suppose we want to change the value of the field edition from \code{2.41} to \code{2.42}. This field is not present in the entry but inherited via a \code{crossref} field. Nevertheless this is not honored by \code{bibtool set}. A new field is added to this entry containing the new value. The other entry is left unchanged. Suppose we want to add a field \code{month} to the entry. This is one place where \BibTeX{} macros are indispensible. Instead of using the constant \verb|"June"| we should always use the macro \code{jun} which is defined by most \BibTeX{} styles. Thus the \BibTeX{} style designer can decide to use the full month name, an abbreviation, or even switch to a different language. If we write \begin{verbatim} $entry set month jun \end{verbatim}%$ \noindent then the result would be the string \code{jun} and not the \BibTeX{} macro. Thus we have to use the flag \code{-concat}. \begin{verbatim} $entry set month jun -concat \end{verbatim}%$ This works fine since Tcl does not distinguish the one string \code{jun} from the list containing \code{jun} as a single element. Nevertheless the correct way would be to use a construction like the following one: \begin{verbatim} $entry set month [list jun] -concat \end{verbatim}%$ If we want to add a specific day as well then this can be done like in the following example\footnote{Note that this does not allow switching the languages any more so easy. But this is not our topic here.} \begin{verbatim} $entry set month [list jun {{~13}}] -concat \end{verbatim}%$ Beware, \BibTool{} does not check the structure or the contents of field values. Thus you have to be careful to use only valid components in order for \BibTeX{} to work properly. \begin{table}[tp] \TclSummary{fields}{\meta{ENTRY}}{This command returns a list of field names in \meta{ENTRY}.} \TclSummaryOO{\meta{ENTRY} forward}{} \TclSummary{forward}{\meta{ENTRY}}{Makes \meta{ENTRY} reference to the successor of its current value. Return \meta{ENTRY} upon success. If none is present then delete the entry handle and return the empty string.} \TclSummaryOO{\meta{ENTRY} get \meta{FIELD} \meta{?-noexpand$\mid$-all?}}{} \TclSummary{get}{\meta{ENTRY} \meta{FIELD} \meta{?-noexpand?} \meta{?-all?}}{This command returns the value of the field \meta{FIELD} in the entry \meta{ENTRY}. The value returned has all strings expanded. If the option \meta{-noexpand} is given then the unexpanded form as it is contained in the database is returned. If the option \meta{-all} is given then the inheritance via crossref is honored. I.e. each missing field is extracted from the crossrefed entry (etc). If the field does not exist then the empty string is returned.} \TclSummaryOO{\meta{ENTRY} missing \meta{FIELD}}{} \TclSummary{missing}{\meta{ENTRY} \meta{FIELD}}{This command returns \code{1} if the field \meta{FIELD} is missing in the entry \meta{ENTRY}. Otherwise it returns \code{0}.} \TclSummaryOO{\meta{ENTRY} remove \meta{FIELD}}{} \TclSummary{remove}{\meta{ENTRY} \meta{FIELD}}{Delete the field \meta{FIELD} from the entry \meta{ENTRY}. If it does not exist then nothing is changed.} \TclSummaryOO{\meta{ENTRY} set \meta{FIELD} \meta{VALUE}}{} \TclSummary{set}{\meta{ENTRY} \meta{FIELD} \meta{VALUE}}{This command changes the value of the field or pseudo field \meta{FIELD} to \meta{VALUE}. The field is added if it has not been present already.} \caption{Summary of field operations}\label{fig:tcl-field} \rule{\textwidth}{.1pt} \end{table} To complete the operations on entry fields we need a method to get rid of a certain field. For this purpose the method \code{bibtool remove} can be used. We have seen this method already on page~\pageref{bibtool:remove}. If a field is given together with the entry then this field is removed from the entry. Thus \begin{verbatim} $entry remove remark \end{verbatim}%$ Deletes the \code{remark} field from the given entry. If the field is not present in the entry given then nothing is done. This can be especially confusing if a field is inherited via a \code{crossref} field. The value can be retrieved with the \code{bibtool get} method even when the field has been removed: \begin{verbatim} $entry remove author $entry get author -all \end{verbatim} The result of the second command is \code{Gerd Neugebauer} even so the field has been deleted before. \section{Key Generation} The generation of new reference keys has been one of the first functionalities present in \BibTool. The keys are generated according to a specification described in detail in the \BibTool{} documentation. Thus it is not repeated here. The format specification can be specified with a resource command (see section~\ref{sec:tcl-resources}. For convenience the command \code{bibtool key.format} is provided. It can be used to set the key format. It is important to construct the argument such that the string which arrives in the resource command is has the proper syntax. This means that you have to be careful which characters might need quoting. The easiest way is to enclose the complete format with braces. Thus nearly everything works as expected. \begin{table}[t] \begin{center}\doublerulesep=.4pt \begin{tabular}{lp{.6\textwidth}}\hline\hline {\it special format}\rule[-1.5ex]{0pt}{4ex} & {\it meaning}\\\hline\rule{0pt}{3ex}% \code{empty} & Use the default key. \\ \code{short} & Use the last names of authors or editors and the first relevant word from the title. \\ \code{long} & Use the names of authors or editors with initials and the first relevant word from the title. \\ \code{new.short} & Like \code{short} but only applied to entries without a key.\\ \code{new.long} & Like \code{long} but only applied to entries without a key.\\[1ex] \hline\hline \end{tabular} \caption{Special format specifiers}\label{tab:special-keys} \end{center} \end{table} Usually the function \code{bibtool key.format} adds the given format specification as a further alternative after the specification already present. Thus it is possible to iteratively construct the specification by giving cases in decreasing order. This exception to this rule are the special specifications shown in Table~\ref{tab:special-keys}. Those special specifiers are not added but they entirely replace the old values. Thus the following instruction can be used to clear the old value before adding new alternatives: \begin{verbatim} bibtool key.format {empty} \end{verbatim} Two practical schemes are provided as convenient abbreviations, namely \code{short} and \code{long}. They use the names of authors or editors of a entry together with the first relevant word of the title. \begin{verbatim} bibtool key.format {short} \end{verbatim} The relevant word is determined by skipping over all words which are added to the list of ignored words with \code{bibtool ignored.word}. This list usually contains articles from different languages. and is initialized at compile time. Now we are ready to generate a new key. This cam be done either globally by applying the function \code{bibtool key} to a database. In this case the new key is generated for each entry in this database. \begin{verbatim} bibtool key $db \end{verbatim}%$ The alternative is to apply they key generation algorithm to a single entry. In this case only the key of this entry is generated. As a side effect the new key of this entry is returned. \begin{verbatim} set key [bibtool key $entry] puts $key \end{verbatim} \INCOMPLETE \begin{table}[tp] \TclSummary{key}{\meta{ENTRY}}{This command creates a new reference key for \meta{ENTRY} according to the specification in effect and stores it in \meta{ENTRY}. This string is returned.} \TclSummary{key}{\meta{DB}}{This command creates a new reference key for each entry in \meta{DB} according to the specification in effect. The empty string is returned.} \TclSummary{key.format}{=\meta{FORMAT}}{} \TclSummary{ignored.word}{=\meta{WORD}}{} \caption{Summary of key generation operations}\label{fig:tcl-keys} \rule{\textwidth}{.1pt} \end{table} \section{Ignored Words} The format specifier for key generation or sorting can request that certain words are ignored. Those words are managed in a global list in \BibTool. Some commands are provided to manipulate this list. Some operations are already provided as resources. Nevertheless a more convenient form is provided as well. The list of ignored words is initialized at compile time. Usually this list contains articles in different languages since they are usually ignored when dealing with titles of publications. This list can be augmented with additional words with the command \code{bibtool add\_ignored}. This command adds add arguments to the list of ignored words. The following example should be superfluous but it illustrates the application of this operation: \begin{verbatim} bibtool add_ignored the a an \end{verbatim}% If you are not satisfied with the compiled in list of ignored words you can clear this list with the command \code{bibtool clear\_ignored}. After this operation the list of ignored words is empty and can be filled from scratch. \begin{verbatim} bibtool clear_ignored \end{verbatim}% The operations above could also be achieved with resource commands. We just need an additional operation which returns the list of ignored words. This operation is performed by \code{bibtool get\_ignored}. The result can be stored in a Tcl variable and used in any way you like: \begin{verbatim} set ignored [bibtool get_ignored] \end{verbatim}% \begin{table}[tp] \TclSummary{ignored.word}{=\meta{WORD}}{} \TclSummary{add\_ignored}{\meta{WORD} \ldots}{This command add all arguments to the list of ignored words.} \TclSummary{clear.ignored.words}{\{\}}{} \TclSummary{clear\_ignored}{}{This command removes all words from the list of ignored words.} \TclSummary{get\_ignored}{}{This command returns the list of ignored words.} \caption{Summary of operations on ignored words}\label{fig:tcl-ignored} \rule{\textwidth}{.1pt} \end{table} \section{\BibTeX{} Macros} In section~\ref{sec:fields} we have already seen \BibTeX{} macros and their expansion when the value of a field is retrieved. Since it is possible to get the value of a field in unexpanded form we need a way to get our hands on the value of a macro. For this purpose the database method \code{bibtool string\_get} is provided. \begin{verbatim} $db string_get BibTool \end{verbatim}%$ \noindent returns the value of the string \code{BibTool} as Tcl string. If this macro is not defined then the empty string is returned. The same remarks as for the values of fields hold for \BibTeX{} macros as well. They can be defined in terms of other macros with the concatenation operation (\verb|#|). If you want to get the unexpanded definition the you have to use the flag \code{-noexpand}. In this case the value returned is a list of components to be concatenated. In this case the string delimters are included to allow you to distinguish strings---which are enclosed in delimiters---from macros. The reverse operation to accessing a macro value is the definition of one. Analogeously to field values the method \code{bibtool string\_set} can be used. This method takes a macro name and a string and arranges that the macro expands to the string given: \begin{verbatim} $db string_set BibTool {{\sffamily BibTool}} \end{verbatim}%$ \INCOMPLETE \begin{verbatim} $db string_set BibTool [list Bib Tool] -concat \end{verbatim}%$ If the value of a macro is the empty string we can not distinguish the case that the macro is not defined at all from the case that the macro is defined and has the empty string as its value. To allow this differtiation the method \code{bibtool string missing} can be used: \begin{verbatim} $db string_missing BibTool \end{verbatim}%$ This method returns \code{1} if the macro \code{BibTool} is not defined and \code{0} otherwise. Thus we would get \code{0} in our example. \begin{table}[tp] \TclSummaryOO{\meta{DB} string\_get \meta{MACRO} \meta{?-global?}}{} \TclSummary{string\_get}{\meta{DB} \meta{MACRO} \meta{?-global?}}{This command retieves the value of the macro \meta{MACRO} from the database \meta{DB} or the global set of macros. If the flag \meta{-global} is given then only the global maros are considered.} \TclSummaryOO{\meta{DB} string\_missing \meta{MACRO} \meta{?-global?}}{} \TclSummary{string\_missing}{\meta{DB} \meta{MACRO} \meta{?-global?}}{This tests whether the macro \meta{MACRO} is defined in the database \meta{DB} or the global macros. If the flag \meta{-global} is given then only the global macros are considered.} \TclSummaryOO{\meta{DB} string\_remove \meta{MACRO} \meta{?-global?}}{} \TclSummary{string\_remove}{\meta{DB} \meta{MACRO} \meta{?-global?}}{Remove the definition of the macro \meta{MACRO} from the database \meta{DB}. If the flag \meta{-global} is given then the global macros are considered only.} \TclSummaryOO{\meta{DB} string\_set \meta{MACRO} \meta{VALUE} \meta{?-global?}}{} \TclSummary{string\_set}{\meta{DB} \meta{MACRO} \meta{VALUE} \meta{?-global?}}{This command assigns the new value \meta{VALUE} to the macro \meta{MACRO} in the database \meta{DB}. If the flag \meta{-global} is given then the change is not made local to the database but in the global set of macros.} \caption{Summary of macro operations}\label{fig:tcl-macro} \rule{\textwidth}{.1pt} \end{table} Since we are now able to distinguish a not existing macro from an empty macro we need a method to get rid of a macro completely. This can be accomplished with the method \code{bibtool string\_remove}: \begin{verbatim} $db string_remove BibTool \end{verbatim}%$ After this operation the macro \code{BibTool} is missing. If the given macro has not been defined in the database then nothing will be done. Otherwise the macro definition is removed from the database. Finally we might be interested to get a complete list of all macros defined for a database. For this purpose the method \code{bibtool strings} can be used which returns the names of all macros as a Tcl list: \begin{verbatim} $db strings \end{verbatim}%$ \section{Embedding \LaTeXTeX{} Macros} \begin{verbatim} $db preamble \end{verbatim}%$ \INCOMPLETE \section{De\TeX ing} When you are dealing with \LaTeXTeX{} commands it is pretty easy to get rid of macros. This cam be done with a \code{regsub} command wich matches the macro names and replaces them by the empty string. Suppose the Tcl variable \code{str} contains a string which should be de\TeX{}ed. \begin{verbatim} regsub -all {\\([^a-zA-Z]|[a-zA-Z]+)} $str {} str \end{verbatim}%$ After the invocation of this command the Tcl variable \code{str} has all macro names stripped. For instance the string \begin{verbatim} M{\"u}ller GmbH{\&}Co. \end{verbatim} \noindent is translated to \begin{verbatim} Muller GmbH{}Co. \end{verbatim} Even if the first substitution might be acceptable for non-German speaking people then the second replancement is by far too aggressive. On the other side we could just replace the backslashes. This can be done with a Tcl command like \begin{verbatim} regsub -all {\\} $str {} str \end{verbatim}%$ \noindent results in \begin{verbatim} M"uller GmbH{&}Co. \end{verbatim} This leaves the \code{\&} but also the crippled \verb|"|. Th eother problem are the arguments. They require matching braces. this can not be expressed with regular expressions. Thus \BibTool{} provides a command to define \TeX{} macros and expand in a string them. The command \code{bibtool tex define} can be used to define \TeX{} macros which should be used for expansion lateron. For our previous example we would have needed the following definitions: \begin{verbatim} bibtool tex define {\&=&} bibtool tex define {\"[1]=#1e} \end{verbatim} The argument of \code{bibtool tex define} is one string containing a control sequence on the left side optionally followed by the number of arguments in brackets. It is completed by a equality sign and the replacement text. If no arguments are given then the macro is assumed to have no arguments. In the example above the first definition makes a macro \verb|\&| without arguments and the second definition makes \verb|\"| a macro with one argment. Like in \LaTeX{} the sequence \verb|#|$n$ represents the $n^{th}$ argument.\footnote{Note that in German ae is the representation of \"a without the umlaut accent.} There is one additional case which has not been described already. If you are a little bit familiar with \TeX{} you might know that you can make a character active and assign a macro to this character. Thus you can omit the leading backslash. This case is coverd in \code{bibtool tex define} as well. If the macro name consists of a single character only which is not the backslash then this character is made active then the remainder is used to assign a macro to it. As a side note I want to note that the reading and macro expansion apparatus of \TeX{} is internally imitated to a certain degree. This included catagory codes. But those catagory codes can (currently) not be modified except by making a character active as described above. Initially no macros are defined in \BibTool. This can also be reached with the following command: \begin{verbatim} bibtool tex reset \end{verbatim} After this command has been executed no macros are defined an no characters are active. But now we want to come to the point where we make use of thsoe definitions. This is achieved with the caommand \code{bibtool tex expand}. All defined macros are replaced by their replacement text. Undefined macros are left unchanged. Thus we could use the following invocation: \begin{verbatim} set str [bibtool tex expand $str] \end{verbatim}%$ With the definitions given above and the value of the Tcl variable \code{str} given in the example above we get as a result the following new value in the Tcl variable \code{str}: \begin{verbatim} M{ue}ller GmbH{&}Co. \end{verbatim} Now we could savely strip the braces (and possibly remaining \TeX{} macros with the method described above. \begin{table}[tp] \TclSummary{tex define}{\meta{mac?[n]?=repl}}{Define the \TeX{} macro or active character \meta{mac}. If \meta{[n]} is given then \meta{n} must be a single digit which is interpreted as the muber of arguments of the macro. The replacement text is \meta{repl}. In ttthe replacement text \code{\#}\meta{n} represents the \meta{n}$^{th}$ macro argument.} \TclSummary{tex expand}{\meta{STRING}}{This command returns the string which results from \meta{STRING} by replacing each defined macro or active character and the optional arguments by it's replacement text.} \TclSummary{tex reset}{}{This command deletes all macros and active characters previously defined.} \caption{Summary of operations on \TeX{} strings}\label{fig:tcl-tex} \rule{\textwidth}{.1pt} \end{table} \section{Name Formatting} \begin{verbatim} bibtool name list \end{verbatim} \INCOMPLETE \begin{verbatim} bibtool name count \end{verbatim} \INCOMPLETE \begin{verbatim} bibtool name format $format $name \end{verbatim} \INCOMPLETE \section{Formatting} In principal Tcl provides everything neccessary to extract the contents of entries and create a formatted string which is stored in a field. Since \BibTool{} started as a tool to autmatically create reference keys for \BibTeX{} databases it has a powerful (and fast) mechanism to extract information from a entry and format it according to a given specification. For a full description we refer to \cite{neugebauer:bibtool}. \begin{table}[t] \begin{center}\doublerulesep=.4pt \begin{tabular}{lp{.6\textwidth}}\hline\hline \textit{format}\rule[-1.5ex]{0pt}{4ex} & \textit{meaning}\\\hline\rule{0pt}{3ex}% \code{\%}\textit{sign pre.post} \code{d(}\textit{field}\code{)} & The \textit{post$^{th}$} number is extracted from the field -- \textit{post} defaults to 1. \textit{pre} digits starting from the right are returned. If \textit{sign} is \code{+} then missing digit are replaced by \code{0}. If \textit{sign} is \code{-} and no number is found then \code{0} is returned instead of the empty string. \\ \code{\%}\textit{sign pre.post} \code{D(}\textit{field}\code{)} & Acts like \code{d} but does not truncate longer numbers to \textit{pre} digits. \\ \code{\%}\textit{sign pre.post} \code{n(}\textit{field}\code{)} & The field is treated as a list of names. Last names are extracted. At most \textit{pre} names are used and remaining names are indicated. At most \textit{post} letters from each name are shown. If \textit{sign} is \code{+} then all letters are translated to upper case. If \textit{sign} is \code{-} then all letters are translated to lower case. \\ \code{\%}\textit{sign pre.post} \code{N(}\textit{field}\code{)} & Acts like \code {n} but appends the initials as well. \\ \code{\%}\textit{sign pre.post} \code{p(}\textit{field}\code{)} & Use the name format \textit{pre} to format at most \textit{post} names accordingly. Translate the case according to the \textit{sign}. \\ \code{\%}\textit{sign pre} \code{s(}\textit{field}\code{)} & Use at most \textit{pre} characters. Translate the case according to the \textit{sign}. \\ \code{\%}\textit{sign pre.post} \code{t(}\textit{field}\code{)} & Use a list of words. The words in the \code{ignored.word} list are not considered. At most \textit{pre} words are shown. At most \textit{post} letters from each word are used. Translate the case according to the \textit{sign}. \code{fmt.titlt.title} is inserted between words. \\ \code{\%}\textit{sign pre.post} \code{T(}\textit{field}\code{)} & Acts like \code{t} but does not ignore words. \\ \code{\%}\textit{sign pre.post} \code{w(}\textit{field}\code{)} & Acts like \code{t} but inserts nothing between words. \\ \code{\%}\textit{sign pre.post} \code{W(}\textit{field}\code{)} & Acts like \code{T} but inserts nothing between words. \\[1ex] \hline\hline \end{tabular} \caption{Format specifiers}\label{tab:formats} \end{center} \end{table} The procedure \code{bibtool format} takes a entry and a format specification and usually returnes a string representation of the format where certain constructions are expanded. If a syntax error is detected an error is raised. To start with the easy case we can state, that any allowed character is passed unchanged from the fromat to the result. The percent sign acts as an escape character which starts an extended command. To produce a single percent sign in the output you have to give two percent signs in the format specifier: \begin{verbatim} $entry format {123%%abc} \end{verbatim}%$ This instruction returns \code{123\%abc}. The percent sign starts a format specifier which is similar to a format specifier of the Tcl \code{format} instruction. But instead of giving arbitrary arguments to be formatted in addition to the format specifier, the format contains the names of fields in parentheses. The values of those fields -- or pseudo-fields -- are formatted according to the format specifier. The general form is as follows: \code{\%} \textit{sign pre.post spec} \code{(}\textit{field}\code{)} We will explain the meaning of the different parts from right to left. \textit{field} is the name of a field or pseudo-field. The value of this field is formatted according to the remaining parts of the format specifier. \textit{spec} is a single letter which determines the main functionality. Details can be found in Table~\ref{tab:formats}. For instance the letter \code{n} denotes name formatting. The other parts of the format specifier are optional and influence the exact operation of the formatting. In any case characters that are not allowed are silently ignored and \TeX{} macros are expanded. In general \textit{spe} can be preceeded by the qualifier \code{\#}. But this is not meaningful in the context of Tcl since it always returns the empty string. Let us finally reconsider our example entry from page \pageref{example:bibtool}. For this entry \code{\$entry} we get the following results: \begin{tabular}{lll} \code{\$entry format "\%n(author)"} &\(\mapsto\)& \code{Neugebauer}\\ \code{\$entry format "\%+.3n(author)"} &\(\mapsto\)& \code{NEU}\\ \code{\$entry format "\%-.2n(author)"} &\(\mapsto\)& \code{ne}\\ \code{\$entry format "\%d(edition)"} &\(\mapsto\)& \code{2}\\ \code{\$entry format "\%d(edition)"} &\(\mapsto\)& \code{2}\\ \code{\$entry format "\%+3.2d(edition)"} &\(\mapsto\)& \code{041}\\ \code{\$entry format "\%2d(year)"} &\(\mapsto\)& \code{97}\\ \code{\$entry format "\%-w(title)"} &\(\mapsto\)& \code{bibtool} \end{tabular} \section{Analyzing a \LaTeX{} aux File} \BibTeX{} uses inormation from the auxiliary files created during a \LaTeX{} run. If you want to write a program to extract the entries used in a document or if you want to write a replacement for \BibTeX{} you need a method to get the information from the aux file. Since the information might be distributed in several aux files if the \LaTeX{} document uses \verb|\include| to combine several subdocuments. Thus it is rather handsome to have a method which collects th required information. This is done by the functions \code{bibtool aux} and \code{bibtool aux -db}. The function \code{bibtool aux} returns a list containing all citations mentioned in the aux file. One key is traeted special. If the key \code{*} is used then all entries in the database should be used. In \LaTeX{} this is accomplished by the macro invocation \begin{verbatim} \nocite{*} \end{verbatim} Thus if a \code{*} is recognized then the list contains only one element namely this star. Otherwise you get the complete list with \begin{verbatim} bibtool aux $auxfile \end{verbatim}%$ If the document contains references to \code{neugebauer:bibtool} and \code{neugebauer:bibtcl} then the following Tcl list is returned: \begin{verbatim} neugebauer:bibtool neugebauer:bibtcl \end{verbatim} The other information which can be extracted from an aux file is the list of databases to be used. This is done with the function \code{bibtool aux databases}. It takes the name of an aux file and returns the list of databases mentioned there: \begin{verbatim} bibtool aux $auxfile -db \end{verbatim}%$ More than one databases can be used in one document by separating them by a comma (\code{,}). In a \LaTeX{} document this might look at follows: \begin{verbatim} \bibliography{db1,db2,db3} \end{verbatim} In this case the function \code{bibtool aux -db} returnes the following list \begin{verbatim} db1 db2 db3 \end{verbatim} If the aux file given to either function does not exist or can not be read then a Tcl error is raised. Thus you should always use \code{catch} and implement your own error recovery routine. \begin{table}[tp] \TclSummary{aux}{\meta{FILE}}{Reads the given \LaTeX{} \code{aux} file and collects a list of all citations. If one citation is \code{*} then this \code{*} is returned. Otherwise a list of all citations found is returned. If the \LaTeX{} document has used \code{\char'134 include} then the respective \code{aux} files are also considered.} \TclSummary{aux}{\meta{FILE} \meta{-db}}{Reads the given \LaTeX{} \code{aux} file and collects a list of all databases requested. If the \LaTeX{} document has used \code{\char'134 include} then the respective \code{aux} files are also considered.} \caption{Summary of operations on aux files}\label{fig:tcl-aux} \rule{\textwidth}{.1pt} \end{table} \section{Recognized Entry Types} In \BibTeX{} any entry has a certain type -- the entry type. \BibTool{} maintains a list of known entry types and complains if a entry is read which has an unknown entry type. Such entries are not stored in the database. Usually the entry types of the standard \BibTeX{} styles are already known to \BibTool. But if you are using some other kind of entry type then this has to be declared in \BibTool. This can be done with the resource command \code{new.entry.type}. \begin{verbatim} bibtool new.entry.type={Law} \end{verbatim} Note that no spaces are allowed around the equality sign and that the braces are neccesary to preserve the case of the letters. This is useful since \BibTeX{} and \BibTool{} normally ignore the case of letters. But the string given as entry type is not only used to determine whether or not a entry can be stored in the database but also as the printing representation of the entry type. Thus in our example it would be possible to have entries of the following kind \begin{verbatim} @law{ ... } @Law{ ... } @LAW{ ... } \end{verbatim} All of those would be accepted and be assigned the same entry type. All of them would be printed like the second example. As a sidemark you should note that \code{new.entry.type} can also be used to redefine the printing representation of existing entry types. Whenever an existing entry type is encountered as argument then just this modification is performed. For a Tcl program it might be necessary to know which entry types are defined in \BibTool. Thus it can present a menu to the user to select the appropriate type. For this purpose the instruction \code{bibtool types} is provided. This can be seen in the following fragment of a program where \code{\$menu} is assumed to contain the path to a previously created \code{menu}. \begin{verbatim} foreach type [bibtool types] { $menu add checkbutton \ -variable entry_type \ -value $type \ -label $type } \end{verbatim}%$ If you run this example you will see that the menu contains normal entry types only. Currently the following entry types are considered special:\medskip \mbox{}\hfill \begin{minipage}{.3\textwidth} COMMENT \\ PREAMBLE \\ STRING \end{minipage}\hfill \begin{minipage}{.3\textwidth} ALIAS \\ INCLUDE \\ MODIFY \end{minipage} \hfill\mbox{}\medskip The three sepcial entry types to the left are well known. The entry types to the right are likely to be introduced in \BibTeX\,1.0. If you want to get a complete list of all entry types you can give the optional argument \code{-all} to the \code{bibtool types} command. Then the special entry types are returned in addition to the normal entry types. \begin{table}[tp] \TclSummary{types}{\meta{?-all?}}{Return the list of defined entry types. Normally all normal entry types are returned. If the option \code{-all} is given then the special entry types are delivered as well. The entry types are returned in some internal order. They are not sorted.} \TclSummary{version}{}{Return the version number of \BibTool.} \caption{Summary of misc operations}\label{fig:tcl-misc} \rule{\textwidth}{.1pt} \end{table} \section{The Version Number} Finally, BibTcl provides a means to get hold of the version number. This can be useful to give this information to the user or to see whether a new enough version is used when older versions might miss some features. I would like to provide means to test for features directly. But until I have descided how this will be implemented the version is the only indicator which can be used. The version number is returned by the function \code{bibtool version}. The return value consists of a number \meta{major}.\meta{minor} where \meta{mayor} is the major version number and \meta{minor} is the minor version number. Additionally some additions may be returned. Thus \begin{verbatim} bibtool version \end{verbatim} \noindent may return \code{2.41} but a value of \code{2.41-a} is also a legal value---even so it is not very likely that you get your hands on such a release. \section{Using \BibTool{} Resources}\label{sec:tcl-resources} Nearly all resource commands of \BibTool{} are accessible through the \code{bibtool} command. If nothing else fits then the argument of the \code{bibtool} command is passed on to the resource evaluator. Since this is done for each single argument this means that special characters have to be protected in a way to ensure that they arrive safely there. For instance the resource evaluator treats the equality sign as optional. Separating spaces are enough. Thus the following two commands have the same effect: \begin{verbatim} bibtool quiet=on bibtool {quiet on} \end{verbatim} Note however that the second form requires the braces to protect the embedded space. \BibTool{} resources can also be queried. Since not each resource command corresponds to a single variable not all resource commands can be used to query values. At least each resource command which corresponds to a string, a boolean, or a numeric value can be queried. Consider the resource instruction from above \code{quiet=on}. This instructions sets the boolean resource \code{quiet}. This variable can be queried with \begin{verbatim} bibtool quiet \end{verbatim} This Tcl command returns the value of the resource variable. Booleans are returned as \code{0} or \code{1} to conform to the Tcl conventions for booleans. \INCOMPLETE \begin{table}[tp] \TclSummary{\meta{RSC\_VARIABLE}}{}{Returns the contents of the resource variable \meta{RSC\_VARIABLE} if this variable is available. Strings, booleans, and numerics are available.} \TclSummary{\meta{RSC}}{\meta{\ldots}}{Passes the resource command \meta{RSC} to the resource evaluator of \BibTool. Each single argument is treated as a separate resource command.} \caption{Summary of resource operations}\label{fig:tcl-rsc} \rule{\textwidth}{.1pt} \end{table} \chapter{Installation}\label{sec:installation} This section is the last one since it is required only once. It describes the installation of the dynamic loadable library. \section{UNIX} \begin{itemize} \item I suppose that you have unpacked \BibTool{}. You should be in the main directory containing the directory \file{BibTcl}. \item Configure and compile \BibTool{}---if not already done. See the files \file{README.md} and \file{INSTALL} there. The object files must be present in this directory. (In a next release a single library will be assembled and the C API might be documented.) \item Find the file \file{tclConfig.sh}. This file is created during the configuration of Tcl and installed with it. One place to search for it is in the directory \file{/usr/local/lib} or wherever Tcl has installed its libraries. Copy this file into the directory \file{BibTcl}. \item Go to the directory \file{BibTcl} and run \code{./configure} This will have a look at your system and find out which properties it has. From this information a \file{Makefile} is created. \item Run \code{make LIBDIR=/usr/local/lib/BibTool} where the path on the right side of the \code{=} should point to the installed \BibTool. This step should produce the shared library and a small Tcl loader \file{bibtool.tcl} which is independent of the architecture. In fact it figures out the architecture and uses the appropriate installed version. \item Run \code{make install LIBDIR=/usr/local/lib/BibTool} This creates a subdirectory of \file{LIBDIR} according to the OS used. This directory contains the shared library as well as the loader script. The loader script can be freely copied to any other place. The shared library must stay in this directory since the location is compiled into the loader script. \end{itemize} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Local Variables: % mode: latex % TeX-master: "bibtcl.ltx" % End: BibTool/BibTcl/bibtool.c0000644000175100017510000024307212254326760014004 0ustar genegene/****************************************************************************** ** bibtool.c ******************************************************************************* ** Author: Gerd Neugebauer **===========================================================================*/ #include #include #include #define OBJECT_PROC /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ int BibtoolObjectCmd(ClientData c, Tcl_Interp *i,int argc, char *argv[]); int BibtoolCmd(ClientData c, Tcl_Interp *i,int argc, char *argv[]); /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ void save_input_file (char *file){} /* main.c */ void save_macro_file (char * file){} /* main.c */ void save_output_file (char * file){} /* main.c */ extern char * bibtool_version; /*---------------------------------------------------------------------------*/ #define MAX_HANDLE_LENGTH 256 static Tcl_HashTable bibtool_table; /* */ static Tcl_HashEntry *ep; /* */ static DB the_db; static char buffer[MAX_HANDLE_LENGTH]; static char * empty = ""; static char * zero = "0"; static char * one = "1"; static char * err_0 = "*** bibtool error '"; static char * err_1 = "': bibtool "; static char * err_2 = "too few arguments"; static char * err_rec = "invalid record"; static char * err_db = "invalid database"; static Tcl_DString ds; #define ErrorExit(FCT) \ Tcl_AppendResult(interp,err_0,FCT,err_1,argv[1],NULL); return TCL_ERROR #define NeedArgs(N) if (argc<=N) { ErrorExit(err_2); } #define CheckArg(N,V) argc>N && strcmp(argv[N],V)==0 #define GetRecord(R,N) \ if ( (R=get__record(N)) == RecordNULL ) { ErrorExit(err_rec); } #define GetDB(D,N) \ if ( (D=get__db(N)) == (DB)NULL ) { ErrorExit(err_db); } #define IsNoRec(S) strchr(S,'/') == NULL #ifdef OBJECT_PROC #define MakeObject(S) \ Tcl_CreateCommand(interp,S,BibtoolObjectCmd,(ClientData)NULL, \ (Tcl_CmdDeleteProc *)NULL) #else #define MakeObject(S) #endif #define THE_MARK 0x100 /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- ** Function: rec_gt() ** Purpose: ** ** ** Arguments: ** r1 ** r2 ** Returns: **___________________________________________________ */ static int rec_gt(r1,r2) /* */ Record r1; /* */ Record r2; /* */ { char * s1 = RecordSortkey(r1); /* */ char * s2 = RecordSortkey(r2); /* */ if ( s1 == NULL || *s1 == '\0' ) s1 = *RecordHeap(r1);/* */ if ( s2 == NULL || *s2 == '\0' ) s2 = *RecordHeap(r2);/* */ return (strcmp(s1,s2) < 0); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: rec_lt() ** Purpose: ** ** ** Arguments: ** r1 ** r2 ** Returns: **___________________________________________________ */ static int rec_lt(r1,r2) /* */ Record r1; /* */ Record r2; /* */ { char * s1 = RecordSortkey(r1); /* */ char * s2 = RecordSortkey(r2); /* */ if ( s1 == NULL || *s1 == '\0' ) s1 = *RecordHeap(r1);/* */ if ( s2 == NULL || *s2 == '\0' ) s2 = *RecordHeap(r2);/* */ return (strcmp(s1,s2) > 0); /* */ } /*------------------------*/ #define REC_BEGINNING 1 #define REC_END 2 #define REC_HERE 0 /*----------------------------------------------------------------------------- ** Function: new__record() ** Purpose: Create a new handle for a record. ** Arguments: ** rec ** pos ** Returns: **___________________________________________________ */ static char * new__record(interp,rec,s_db,pos) /* */ Tcl_Interp *interp; /* */ Record rec; /* */ char *s_db; /* */ int pos; /* */ { int i; /* */ char *name; /* */ /* */ if ( rec == NULL ) return empty; /* */ /* */ switch (pos) /* */ { /* */ case REC_BEGINNING: /* */ while (PrevRecord(rec)!=RecordNULL) /* */ rec = PrevRecord(rec); /* */ while ( rec && RecordIsDELETED(rec) ) /* */ rec = NextRecord(rec); /* */ break; /* */ case REC_END: /* */ while (NextRecord(rec)!=RecordNULL) /* */ rec = NextRecord(rec); /* */ while ( rec && RecordIsDELETED(rec) ) /* */ rec = PrevRecord(rec); /* */ break; /* */ } /* */ /* */ if ( rec == NULL ) return empty; /* */ /* */ i = 1; /* */ do /* */ { sprintf(buffer,"%s/=%d=",s_db,i++); /* */ } while (Tcl_FindHashEntry(&bibtool_table,buffer) != NULL);/* */ /* */ if ( (name = malloc(strlen(buffer)+1)) == NULL ) return empty;/* */ strcpy(name,buffer); /* */ /* */ MakeObject(name); /* */ Tcl_SetHashValue(Tcl_CreateHashEntry(&bibtool_table,name,&i),/* */ (ClientData)rec); /* */ return name; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: get__record() ** Purpose: ** ** ** Arguments: ** name ** Returns: **___________________________________________________ */ static Record get__record(name) /* */ char *name; /* */ { char *cp; /* */ Record rec; /* */ Tcl_HashEntry *ep2; /* */ /* */ if ( strlen(name) >= MAX_HANDLE_LENGTH ) /* */ { return RecordNULL; } /* */ strcpy(buffer,name); /* */ if ( (cp = strchr(buffer,'/')) == NULL ) /* */ { return RecordNULL; } /* */ *cp = '\0'; /* */ /* */ if ( NULL == (ep2=Tcl_FindHashEntry(&bibtool_table,buffer)) )/* */ { return RecordNULL; } /* */ the_db = (DB) Tcl_GetHashValue(ep2); /* */ /* */ if (NULL == (ep=Tcl_FindHashEntry(&bibtool_table,name)) )/* */ { Tcl_DeleteHashEntry(ep2); /* */ return RecordNULL; /* */ } /* */ /* */ rec = (Record)Tcl_GetHashValue(ep); /* */ if ( RecordIsDELETED(rec) ) /* */ { Tcl_DeleteHashEntry(ep); /* */ return RecordNULL; /* */ } /* */ return rec; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: new__db() ** Purpose: ** ** ** Arguments: ** ** Returns: **___________________________________________________ */ static char * new__db() /* */ { int i; /* */ char *name; /* */ /* */ i = 1; /* */ do /* */ { sprintf(buffer,"=BibTcl=%d=",i++); /* */ } while (Tcl_FindHashEntry(&bibtool_table,buffer) != NULL);/* */ /* */ if ( (name = malloc(strlen(buffer)+1)) == NULL ) return empty;/* */ strcpy(name,buffer); /* */ the_db = new_db(); /* */ Tcl_SetHashValue(Tcl_CreateHashEntry(&bibtool_table,name,&i),/* */ (ClientData)the_db); /* */ return name; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: get__db() ** Purpose: ** ** ** Arguments: ** name ** Returns: **___________________________________________________ */ static DB get__db(name) /* */ char *name; /* */ { /* */ ep = Tcl_FindHashEntry(&bibtool_table,name); /* */ return (ep==NULL?(DB)NULL:(DB)Tcl_GetHashValue(ep));/* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: yes() ** Purpose: ** ** ** Arguments: ** db ** rec ** Returns: **___________________________________________________ */ static int yes(db,rec) /* */ DB db; /* */ Record rec; /* */ { return 1; /* */ } /*------------------------*/ static Tcl_Interp *ip; /*----------------------------------------------------------------------------- ** Function: aux__1i() ** Purpose: ** ** ** Arguments: ** s ** Returns: **___________________________________________________ */ static int aux__1i(s) /* */ char * s; /* */ { /* */ Tcl_AppendElement(ip,s); /* */ return 1; } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: aux__0() ** Purpose: ** ** ** Arguments: ** s ** Returns: nothing **___________________________________________________ */ static void aux__0(s) char *s; { } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: aux__1() ** Purpose: ** ** ** Arguments: ** s ** Returns: **___________________________________________________ */ static void aux__1(s) /* */ char * s; /* */ { /* */ Tcl_AppendElement(ip,s); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_aux() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_aux(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { void (*fct)_ARG((char*)); /* */ /* */ ip = interp; /* */ NeedArgs(2); /* */ if ( CheckArg(3,"-db") ) fct = aux__1; /* */ else fct = aux__0; /* */ clear_aux(); /* */ if ( read_aux(argv[2],fct,0) ) /* */ { ErrorExit("aux file not readable"); } /* */ /* */ if ( CheckArg(3,"-db") ) {} /* */ else /* */ { if ( foreach_aux(aux__1i) ) /* */ { Tcl_SetResult(interp,"*",TCL_STATIC); } /* */ } /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_count() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_count(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ int *cnt,i; /* */ NeedArgs(3); /* */ GetDB(db,argv[2]); /* */ Tcl_UnsetVar(interp,argv[3],0); /* */ cnt = db_count(db,&i); /* */ while ( 0 <= --i ) /* */ { sprintf(buffer, /* */ "set %s(%s) %d", /* */ argv[3],EntryName(i),cnt[i]); /* */ Tcl_Eval(interp,buffer); /* */ } /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_delete() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_delete(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ DB db; /* */ /* */ NeedArgs(2); /* */ /* */ if ( IsNoRec(argv[2]) ) { GetDB(db,argv[2]); free_db(db); Tcl_DeleteHashEntry(ep); } /* */ else /* */ { GetRecord(rec,argv[2]); Tcl_DeleteHashEntry(ep); } /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_equal() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_equal(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec1, rec2; /* */ /* */ NeedArgs(3); /* */ GetRecord(rec1,argv[2]); /* */ GetRecord(rec2,argv[3]); /* */ Tcl_SetResult(interp,(rec1==rec2?one:zero),TCL_STATIC);/* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_dup() ** Purpose: Duplicate a record handle. ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_dup(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ /* */ NeedArgs(2); /* */ GetRecord(rec,argv[2]); /* */ Tcl_SetResult(interp, /* */ new__record(interp, /* */ rec, /* */ argv[2], /* */ REC_HERE), /* */ TCL_VOLATILE); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_fields() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_fields(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ int n; /* */ Uchar **cpp; /* */ /* */ NeedArgs(1); /* */ GetRecord(rec,argv[2]); /* */ cpp = RecordHeap(rec); /* */ n = RecordFree(rec); /* */ for ( n -= 2, cpp += 2; /* */ n > 0; /* */ n -= 2 ) /* */ { /* */ if (*cpp) { Tcl_AppendElement(interp, /* */ (char*)(*cpp)); }/* */ cpp++; cpp++; /* */ } /* */ /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_find() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_find(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ /* */ NeedArgs(3); /* */ GetDB(db,argv[2]); /* */ Tcl_SetResult(interp, /* */ new__record(interp, /* */ db_find(db,sym_add(argv[3],0)),/* */ argv[2], /* */ REC_HERE), /* */ TCL_VOLATILE); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_format() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_format(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ StringBuffer *sb; /* */ int ret; /* */ NeedArgs(3); /* */ GetRecord(rec,argv[2]); /* */ if ( (sb=sbopen()) == NULL ) /* */ { return TCL_ERROR; /* */ } ret = apply_fmt(sb,argv[3],rec,the_db); Tcl_AppendResult(interp,sbflush(sb),NULL); sbclose(sb); return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_get() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_get(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ int n; /* */ char *s; /* */ int all = 0; /* */ int xref_limit = rsc_xref_limit; /* */ int key_expand = rsc_key_expand_macros; /* */ /* */ NeedArgs(3); /* */ GetRecord(rec,argv[2]); /* */ /* */ rsc_key_expand_macros = 1; /* */ for ( n=4; argc>n; n++ ) /* */ { if ( strcmp(argv[n],"-noexpand") == 0 ) /* */ { rsc_key_expand_macros = 0; } /* */ else if ( strcmp(argv[n],"-all") == 0 ) /* */ { all = 1; } /* */ } if ( !all ) rsc_xref_limit = 1; if ( (s=get_field(the_db,rec,symbol(argv[3]))) == NULL )/* */ { Tcl_SetResult(interp,empty,TCL_STATIC); } else if ( rsc_key_expand_macros ) { Tcl_SetResult(interp,s,TCL_VOLATILE); } /* */ else { int level; char c, *cp, *t, ec; Tcl_DStringInit(&ds); t = s; for ( cp=s; *cp; cp++ ) { if ( *cp == '"' || *cp == '{' ) { if ( *cp == '"' ) { ec = '"'; level = 0; } else { ec = '}'; level = -1; } for ( t = cp++; *cp && (level>0 || *cp != ec); cp ++ ) { switch ( *cp ) { case '{': level++; break; case '}': level--; break; } } if ( *cp ) { c = *++cp; *cp = '\0'; Tcl_DStringAppendElement(&ds,t); *cp = c; t = cp; } } else if ( isdigit(*cp) ) { do { ++cp; } while (isdigit(*cp)); c = *cp; *cp = '\0'; Tcl_DStringAppendElement(&ds,t); *cp = c; t = cp--; } else if ( strchr("#%'(){}\",=",*cp) == NULL && !isspace(*cp) ) { do { ++cp; } while ( *cp && !isdigit(*cp) && !isspace(*cp) && strchr("#%'(){}\",=",*cp) == NULL ); c = *cp; *cp = '\0'; Tcl_DStringAppendElement(&ds,t); *cp = c; t = cp--; } } /* */ Tcl_DStringResult(interp,&ds); /* */ } /* */ /* */ rsc_xref_limit = xref_limit; /* */ rsc_key_expand_macros = key_expand; /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_ig_clear() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_ig_clear(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { /* */ clear_ignored_words(); /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_ig_add() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_ig_add(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { int i; /* */ for (i=2;i 0; /* */ n -= 2 ) /* */ { if (*cpp && case_cmp((char*)(*cpp),argv[3])==0 )/* */ { Tcl_SetResult(interp,zero,TCL_STATIC); /* */ return TCL_OK; /* */ } /* */ cpp++; cpp++; /* */ } /* */ /* */ Tcl_SetResult(interp,one,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_move() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** dir ** Returns: **___________________________________________________ */ static int bt_move(interp,argc,argv,dir) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ int dir; /* */ { Record rec; /* */ /* */ NeedArgs(1); /* */ GetRecord(rec,argv[2]); /* */ /* */ if ( dir > 0 ) /* */ { do /* */ { rec = NextRecord(rec); /* */ } while ( rec != RecordNULL && RecordIsDELETED(rec) );/* */ } /* */ else /* */ { do /* */ { rec = PrevRecord(rec); /* */ } while ( rec != RecordNULL && RecordIsDELETED(rec) );/* */ } /* */ /* */ if ( rec==RecordNULL ) /* */ { Tcl_DeleteHashEntry(ep); /* */ Tcl_SetResult(interp,empty,TCL_VOLATILE); /* */ return TCL_OK; /* */ } /* */ /* */ Tcl_SetHashValue(ep,(ClientData)rec); /* */ Tcl_SetResult(interp,argv[2],TCL_VOLATILE); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_name() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_name(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { char *s, *t, *tmp; /* */ int i; /* */ /* */ NeedArgs(3); /* */ /* */ if ( strcmp(argv[2],"list")==0 ) /* */ { /* */ s = argv[3]; /* */ while (is_space(*s)) s++; /* */ if ( *s == '\0' ) return TCL_OK; /* */ s = t = tmp = new_string(s); /* */ while ( *s ) /* */ { /* */ if ( (*s == ' ' || *s == '\t' ) && /* */ strncmp(s+1,"and",3) == 0 && /* */ (s[4] == ' ' || s[4] == '\t' ) /* */ ) /* */ { *s = '\0'; /* */ Tcl_AppendElement(interp,t); /* */ s += 5; /* */ while (is_space(*s)) s++; /* */ t = s; /* */ } /* */ else /* */ { s++; /* */ } /* */ } /* */ if (*t) Tcl_AppendElement(interp,t); /* */ /* */ free(tmp); /* */ } /* */ else if ( strcmp(argv[2],"count")==0 ) /* */ { char buffer[32]; /* */ /* */ s = argv[3]; /* */ i = 0; /* */ while (is_space(*s)) s++; /* */ if ( *s ) /* */ { i++; /* */ while ( *s ) /* */ { /* */ if ( (*s == ' ' || *s == '\t' ) && /* */ strncmp(s+1,"and",3) == 0 && /* */ (s[4] == ' ' || s[4] == '\t' ) /* */ ) /* */ { /* */ i++; /* */ s += 5; /* */ } /* */ else /* */ { s++; /* */ } /* */ } /* */ } /* */ sprintf(buffer,"%d",i); /* */ Tcl_SetResult(interp,buffer,TCL_VOLATILE); /* */ } else if ( strcmp(argv[2],"format")==0 ) { NeedArgs(4); /* */ } else { Tcl_SetResult(interp,"unknown subcommand",TCL_STATIC);/* */ return TCL_ERROR; /* */ } /* */ /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_new() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_new(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { char *sdb; /* */ int i; /* */ /* */ if ( (sdb=new__db()) == NULL ) /* */ { ErrorExit("db creation failed"); } /* */ /* */ for ( i=2; i 3 ) /* */ { remove_field(sym_add(argv[3],0),rec); } /* */ else /* */ { SetRecordDELETED(rec); } /* */ /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: search__() ** Purpose: ** ** ** Arguments: ** rec ** argc ** argv ** Returns: **___________________________________________________ */ static int search__(rec,argc,argv) Record rec; int argc; char *argv[]; { char *s = argv[3]; if ( RecordIsDELETED(rec) ) return 0; return 1; } /*----------------------------------------------------------------------------- ** Function: bt_search() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_search(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ DB db; /* */ /* */ NeedArgs(3); /* */ /* */ if ( IsNoRec(argv[2]) ) { GetDB(db,argv[2]); rec = DBnormal(db); if ( rec != RecordNULL ) { while ( PrevRecord(rec) != RecordNULL ) { rec = PrevRecord(rec); } while ( rec ) { if ( search__(rec,argc,argv) ) { Tcl_SetResult(interp, /* */ new__record(interp, /* */ rec, /* */ argv[2], /* */ REC_HERE), /* */ TCL_VOLATILE); /* */ return TCL_OK; /* */ } rec = NextRecord(rec); } } } /* */ else /* */ { GetRecord(rec,argv[2]); rec = NextRecord(rec); while ( rec ) { if ( search__(rec,argc,argv) ) { Tcl_SetHashValue(ep,(ClientData)rec); /* */ Tcl_SetResult(interp,argv[2],TCL_VOLATILE);/* */ } rec = NextRecord(rec); } Tcl_DeleteHashEntry(ep); /* */ Tcl_SetResult(interp,empty,TCL_VOLATILE); /* */ return TCL_OK; /* */ } /* */ /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_set() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_set(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ int n; /* */ /* */ NeedArgs(4); /* */ GetRecord(rec,argv[2]); /* */ /* */ #define If_Separator_(S,N) if (strcmp(argv[3],S)==0) set_separator(N,argv[4]) /* */ if ( *argv[3] == '$' ) /* */ { /* */ if ( strcmp(argv[3],"$key") == 0 ) /* */ { RecordOldKey(rec) /* */ = *RecordHeap(rec) = symbol(argv[4]); /* */ } /* */ else if ( strcmp(argv[3],"$source") == 0 ) /* */ { RecordSource(rec) = symbol(argv[4]); } /* */ else if ( strcmp(argv[3],"$type") == 0 ) /* */ { if ( (n = find_entry_type(argv[4])) < 0 ) /* */ { ErrorExit("undefined entry type"); } /* */ RecordType(rec) = n; /* */ } /* */ else if ( strcmp(argv[3],"$sortkey") == 0 ) /* */ { RecordSortkey(rec) = symbol(argv[4]); } /* */ else If_Separator_("$default.key" ,0); /* */ else If_Separator_("$fmt.inter.name" ,1); /* */ else If_Separator_("$fmt.name.pre" ,2); /* */ else If_Separator_("$fmt.name.name" ,3); /* */ else If_Separator_("$fmt.name.title" ,4); /* */ else If_Separator_("$fmt.title.title",5); /* */ else If_Separator_("$fmt.key.number" ,6); /* */ else If_Separator_("$fmt.et.al" ,7); /* */ else /* */ { /* */ Tcl_SetResult(interp,"illegal key",TCL_STATIC);/* */ return TCL_ERROR; /* */ } /* */ } /* */ else if ( *argv[3] == '@' ) /* */ { } else /* */ { push_to_record(rec, /* */ symbol(argv[3]), /* */ symbol(argv[4])); /* */ } /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_sort() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_sort(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ Record rec; /* */ int i; /* */ int (*fct)(); /* Function pointer */ /* */ NeedArgs(2); /* */ if ( IsNoRec(argv[2]) ) /* */ { /* */ GetDB(db,argv[2]); /* */ if ( (rec=DBnormal(db)) != RecordNULL ) /* */ { /* */ while ( PrevRecord(rec) != RecordNULL ) /* */ { rec = PrevRecord(rec); } /* */ if ( CheckArg(3,"-generate") || /* */ CheckArg(4,"-generate") ) /* */ { /* */ for ( ; rec!=RecordNULL; rec=NextRecord(rec) )/* */ { make_sort_key(db,rec); } /* */ } /* */ else /* */ { /* */ for ( ; rec!=RecordNULL; rec=NextRecord(rec) )/* */ { if ( RecordSortkey(rec) == NULL /* */ || *RecordSortkey(rec) == '\0' ) /* */ { RecordSortkey(rec) = *RecordHeap(rec); }/* */ } /* */ } /* */ /* */ i = rsc_sort_reverse; /* */ if ( CheckArg(3,"-reverse") || /* */ CheckArg(4,"-reverse") ) { i = !i; } /* */ if ( i ) fct = rec_lt; /* */ else fct = rec_gt; /* */ db_sort(db,fct); /* */ } /* */ } /* */ else /* */ { /* */ GetRecord(rec,argv[2]); /* */ sort_record(rec); /* */ } /* */ /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_sput() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_sput(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ /* */ NeedArgs(2); /* */ GetRecord(rec,argv[2]); /* */ /* */ Tcl_SetResult(interp, /* */ sput_record(rec,the_db,"@"), /* */ TCL_VOLATILE); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_str_get() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_str_get(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ Uchar * s; /* */ /* */ NeedArgs(2); /* */ GetDB(db,argv[2]); /* */ /* */ for (s=argv[3];*s;s++) { *s = ToLower(*s); } s = db_string(db,symbol(argv[3]),-1); /* */ if ( s == NULL ) /* */ { Tcl_SetResult(interp,empty,TCL_STATIC); } /* */ else /* */ { Tcl_SetResult(interp,s,TCL_VOLATILE); } /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_str_missing() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_str_missing(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ Uchar * s; /* */ /* */ NeedArgs(2); /* */ GetDB(db,argv[2]); /* */ /* */ for (s=argv[3];*s;s++) { *s = ToLower(*s); } if ( CheckArg(4,"-global") ) { s = (look_macro(argv[3],-1)==NULL?"1":"0"); } else { s = ( db_string(db,symbol(argv[3]),-1) == NULL /* */ ?"1":"0"); /* */ } /* */ Tcl_SetResult(interp,s,TCL_STATIC); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_str_remove() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_str_remove(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ Record rec; /* */ Uchar *s; /* */ /* */ NeedArgs(2); /* */ GetDB(db,argv[2]); /* */ /* */ for (s=argv[3];*s;s++) { *s = ToLower(*s); } /* */ s = symbol(argv[3]); /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ /* */ if ( CheckArg(4,"-global") ) { def_macro(s,NULL,0); } else { for ( rec=DBstring(db); rec ; rec=NextRecord(rec) ) { if ( RecordHeap(rec)[0] == s ) { DBstring(db) = unlink_record(rec); return TCL_OK; } /* */ } /* */ } /* */ /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_str_set() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_str_set(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ Record rec; /* */ Uchar *s, *t; /* */ /* */ NeedArgs(4); /* */ GetDB(db,argv[2]); /* */ /* */ for (s=argv[3];*s;s++) { *s = ToLower(*s); } /* */ s = symbol(argv[3]); /* */ t = symbol(argv[4]); /* */ Tcl_SetResult(interp,empty,TCL_STATIC); /* */ /* */ if ( CheckArg(5,"-global") ) /* */ { def_macro(s,t,0); } else { for ( rec=DBstring(db); rec ; rec=NextRecord(rec) ) { if ( RecordHeap(rec)[0] == s ) { RecordHeap(rec)[1] = t; return TCL_OK; } } rec = new_record(BIB_STRING,2); RecordHeap(rec)[0] = s; RecordHeap(rec)[1] = t; if ( DBstring(db) ) { Record r; PrevRecord(rec) = DBstring(db); if ( (r=NextRecord(DBstring(db))) ) { NextRecord(rec) = r; PrevRecord(NextRecord(r)) = rec; } NextRecord(DBstring(db)) = rec; } DBstring(db) = rec; } /* */ /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: str__1() ** Purpose: ** ** ** Arguments: ** s ** t ** Returns: **___________________________________________________ */ static int str__1(s,t) /* */ char *s; /* */ char *t; /* */ { Tcl_AppendElement(ip,s); /* */ return 1; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_strings() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_strings(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ Record rec; /* */ /* */ NeedArgs(2); /* */ GetDB(db,argv[2]); /* */ if ( CheckArg(3,"-global") ) { ip = interp; foreach_macro(str__1); } else { if ( (rec=DBstring(db)) ) /* */ { /* */ while ( PrevRecord(rec) ) /* */ { rec = PrevRecord(rec); } /* */ /* */ while ( rec ) /* */ { Tcl_AppendElement(interp,RecordHeap(rec)[0]);/* */ rec = NextRecord(rec); /* */ } /* */ } /* */ } /* */ /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_tex() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_tex(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Uchar *s; /* */ int kept = 0; /* */ char q[2]; /* */ /* */ NeedArgs(2); /* */ switch ( *argv[2] ) /* */ { /* */ case 'd': /* */ if (strcmp(argv[2],"define") == 0) /* */ { /* */ NeedArgs(3); /* */ TeX_def(argv[3]); return TCL_OK; } break; case 'e': if (strcmp(argv[2],"expand") == 0) { NeedArgs(3); /* */ q[1] = '\0'; TeX_open_string(argv[3]); while ( TeX_read(q,&s) ) /* */ { if ( kept ) /* */ { if ( isalpha(*q) ) Tcl_AppendResult(interp," ",NULL);/* */ kept = 0; /* */ } /* */ Tcl_AppendResult(interp,q,NULL); if ( s ) /* */ { Tcl_AppendResult(interp,s,NULL); kept = isalpha(*s); /* */ } /* */ } /* */ TeX_close(); return TCL_OK; } break; case 'r': if (strcmp(argv[2],"reset") == 0) { TeX_reset(); return TCL_OK; } break; } ErrorExit(argv[2]); /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_types() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_types(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { char *s; /* */ int i; /* */ /* */ i = ( CheckArg(2,"-all") ? 0 : 6); /* */ /* */ for ( s=get_entry_type(i); /* */ s != NULL; /* */ s=get_entry_type(++i) ) /* */ { Tcl_AppendElement(interp,s); } /* */ /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_valid() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_valid(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { Record rec; /* */ /* */ NeedArgs(2); /* */ if ( IsNoRec(argv[2]) ) /* */ { Tcl_SetResult(interp,(get__db(argv[2])?one:zero),TCL_STATIC);/* */ } /* */ else if ( (rec=get__record(argv[2])) == RecordNULL )/* */ { Tcl_SetResult(interp,zero,TCL_STATIC); /* */ } /* */ else if ( argc == 3 ) /* */ { Tcl_SetResult(interp,one,TCL_STATIC); /* */ } /* */ else if ( CheckArg(3,"-next") ) /* */ { Tcl_SetResult(interp,(NextRecord(rec)?one:zero),TCL_STATIC);/* */ } /* */ else if ( CheckArg(3,"-previous") ) /* */ { Tcl_SetResult(interp,(PrevRecord(rec)?one:zero),TCL_STATIC);/* */ } /* */ else /* */ { ErrorExit("unknown option"); /* */ } /* */ /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: bt_write() ** Purpose: ** ** ** Arguments: ** interp ** argc ** argv ** Returns: **___________________________________________________ */ static int bt_write(interp,argc,argv) /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { DB db; /* */ FILE *file; /* */ char * mode = "w"; /* */ /* */ NeedArgs(3); /* */ GetDB(db,argv[2]); /* */ if ( CheckArg(4,"-append") ) { mode = "a"; } /* */ /* */ if ( *argv[3] == '\0' ) /* */ { file = stdout; } /* */ else if ( (file=fopen(argv[3],mode))==NULL ) /* */ { ErrorExit("file open error"); } /* */ /* */ print_db(file,db,"pisnmac"); /* */ /* */ if ( file != stdout ) fclose(file); /* */ /* */ Tcl_SetResult(interp,argv[2],TCL_VOLATILE); /* */ return TCL_OK; /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: BibtoolCmd() ** Purpose: ** ** Arguments: ** ClientData clientData ** Tcl_Interp *interp ** int argc ** char* argv[] ** Returns: **___________________________________________________ */ int BibtoolCmd(clientData, interp, argc, argv) /* */ ClientData clientData; /* */ Tcl_Interp *interp; /* */ int argc; /* */ char *argv[]; /* */ { char *s; /* */ /* */ if ( argc < 2 ) /* */ { Tcl_SetResult(interp,bibtool_version,TCL_STATIC);/* */ return TCL_OK; /* */ } /* */ /* */ #ifdef DEBUG { int i; /* */ for ( i=0; i>$@ INST_DIR = `echo 'puts $(LIBDIR)/$$tcl_platform(os)$$tcl_platform(osVersion)'|$(TCLSH)` bibtcl.aux bibtcl.idx: bibtcl.tex bibtcl.ltx $(LATEX) bibtcl.ltx bibtcl.dvi: bibtcl.tex bibtcl.ltx bibtcl.bbl bibtcl.ind $(LATEX) bibtcl.ltx $(LATEX) bibtcl.ltx bibtcl.ind: bibtcl.idx $(MAKEINDEX) -s bibtool.ist bibtcl bibtcl.bbl: bibtcl.bib bibtcl.aux $(BIBTEX) bibtcl install: bibtool${SHLIB_SUFFIX} bibtool.tcl -mkdir $(INST_DIR) cp bibtool${SHLIB_SUFFIX} bibtool.tcl $(INST_DIR) clean: rm -f *.o *${SHLIB_SUFFIX} config.cache config.log config.status lib.exp distclean: clean rm -f Makefile status: @echo $(LIBDIR) BibTool/BibTcl/configure0000755000175100017510000007034510562532304014107 0ustar genegene#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.12 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= 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=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -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 ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$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" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$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) # 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 << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$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" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) 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) 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" ;; -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 ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.12" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=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" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=bibtool.c # 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 its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. 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 if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi for ac_prog in tclsh tclsh-8.0 tclsh-8.1 tclsh-8.2 tclsh-8.3 tclx do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:528: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_TCLSH'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else case "$TCLSH" in /*) ac_cv_path_TCLSH="$TCLSH" # Let the user override the test with a path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_TCLSH="$ac_dir/$ac_word" break fi done IFS="$ac_save_ifs" ;; esac fi TCLSH="$ac_cv_path_TCLSH" if test -n "$TCLSH"; then echo "$ac_t""$TCLSH" 1>&6 else echo "$ac_t""no" 1>&6 fi test -n "$TCLSH" && break done if test -z "$TCLSH" ; then echo "configure: warning: tclsh not found. Ensure that a properly installed tclsh is on your path or live without BibTcl." 1>&2 exit 0 fi # Recover information that Tcl computed with its configure script. echo $ac_n "checking for tcl configuration file""... $ac_c" 1>&6 echo "configure:569: checking for tcl configuration file" >&5 CONFIG_FILE=`echo 'puts [file join [file dirname [info library]] tclConfig.sh]' | $TCLSH` if test -f $CONFIG_FILE ; then echo "$ac_t""$CONFIG_FILE" 1>&6 elif test -f tclConfig.sh ; then CONFIG_FILE=tclConfig.sh echo "$ac_t""$CONFIG_FILE" 1>&6 else echo "configure: warning: not found. Ensure that a properly installed tclsh is on your path." 1>&2 exit 1 fi . $CONFIG_FILE CC=$TCL_CC SHLIB_CFLAGS=$TCL_SHLIB_CFLAGS SHLIB_LD=$TCL_SHLIB_LD SHLIB_LD_LIBS=$TCL_SHLIB_LD_LIBS SHLIB_SUFFIX=$TCL_SHLIB_SUFFIX SHLIB_VERSION=$TCL_SHLIB_VERSION TCL_LIBS=$TCL_LIBS TCL_VERSION=$TCL_VERSION TCL_PREFIX=$TCL_PREFIX trap '' 1 2 15 cat > confcache <<\EOF # 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. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # 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. (set) 2>&1 | case `(ac_space=' '; set) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.12" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@TCLSH@%$TCLSH%g s%@CC@%$CC%g s%@SHLIB_CFLAGS@%$SHLIB_CFLAGS%g s%@SHLIB_LD@%$SHLIB_LD%g s%@SHLIB_LD_LIBS@%$SHLIB_LD_LIBS%g s%@SHLIB_SUFFIX@%$SHLIB_SUFFIX%g s%@SHLIB_VERSION@%$SHLIB_VERSION%g s%@TCL_BUILD_LIB_SPEC@%$TCL_BUILD_LIB_SPEC%g s%@TCL_LIBS@%$TCL_LIBS%g s%@TCL_VERSION@%$TCL_VERSION%g s%@TCL_PREFIX@%$TCL_PREFIX%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 BibTool/BibTcl/configure.in0000644000175100017510000000250010562532304014475 0ustar genegenednl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run to configure the dnl Makefile in this directory. AC_INIT(bibtool.c) AC_PATH_PROGS(TCLSH,tclsh tclsh-8.0 tclsh-8.1 tclsh-8.2 tclsh-8.3 tclx,) if test -z "$TCLSH" ; then AC_MSG_WARN(tclsh not found. Ensure that a properly installed tclsh is on your path or live without BibTcl.) exit 0 fi # Recover information that Tcl computed with its configure script. AC_MSG_CHECKING(for tcl configuration file) CONFIG_FILE=`echo 'puts [[file join [file dirname [info library]] tclConfig.sh]]' | $TCLSH` if test -f $CONFIG_FILE ; then AC_MSG_RESULT($CONFIG_FILE) elif test -f tclConfig.sh ; then CONFIG_FILE=tclConfig.sh AC_MSG_RESULT($CONFIG_FILE) else AC_MSG_WARN(not found. Ensure that a properly installed tclsh is on your path.) exit 1 fi . $CONFIG_FILE CC=$TCL_CC AC_SUBST(CC) SHLIB_CFLAGS=$TCL_SHLIB_CFLAGS AC_SUBST(SHLIB_CFLAGS) SHLIB_LD=$TCL_SHLIB_LD AC_SUBST(SHLIB_LD) SHLIB_LD_LIBS=$TCL_SHLIB_LD_LIBS AC_SUBST(SHLIB_LD_LIBS) SHLIB_SUFFIX=$TCL_SHLIB_SUFFIX AC_SUBST(SHLIB_SUFFIX) SHLIB_VERSION=$TCL_SHLIB_VERSION AC_SUBST(SHLIB_VERSION) AC_SUBST(TCL_BUILD_LIB_SPEC) TCL_LIBS=$TCL_LIBS AC_SUBST(TCL_LIBS) TCL_VERSION=$TCL_VERSION AC_SUBST(TCL_VERSION) TCL_PREFIX=$TCL_PREFIX AC_SUBST(TCL_PREFIX) AC_OUTPUT(Makefile) BibTool/BibTcl/dina4.sty0000644000175100017510000000003310562704521013725 0ustar genegene!../Doc/dina4.styBibTool/BibTcl/main.tcl0000644000175100017510000000155512254327002013622 0ustar genegene#!/usr/local/bin/wish -f ###---------------------------------------------------------------------------- ### main.tcl ###---------------------------------------------------------------------------- set infiles {} set outfile {} set macrofile {} set the_db [new] for {set i 0} {$i<$argc} {incr i} { set arg [lindex $argv $i] if { $arg == "-o" } { incr i set outfile [lindex $argv $i] } else if { $arg == "-q" } { bibtool quiet=[eval ![bibtool quiet]] } else if { $arg == "-s" } { bibtool sort=[eval ![bibtool sort]] } else if { $arg == "-S" } { bibtool sort=[eval ![bibtool sort]] bibtool sort.reverse=[eval ![bibtool sort.reverse]] } else { lappend infiles $arg } } foreach file $infiles { bibtool read $the_db $file } if {[bibtool make.key]} { } else { } if {[bibtool sort]} { bibtool sort $the_db } bibtool write $outfile BibTool/BibTcl/README0000644000175100017510000000576510562532304013064 0ustar genegene This directory contains a PRE-ALPHA release of a BibTool-Tcl integration. The functionality of BibTool is made available through a dynamic loadable library to Tcl. This module has been tested against Tcl 7.6 and Tcl 8.0. These files are included in the distribution of BibTool to get some kind of feedback. If you try/port/improve it contact me please. The implementation is by far not complete. Thus the usual rules apply: incompatible changes might occur. Since I don't know how to figure out the proper ways to set up things automatically yet the installation is a little bit awkward (Also remember that this is a pre-alpha release). I know how to do it on UNIX systems only. If you know the procedure for other systems drop me a mail such that I can improve this description. WINDOWS ======= Tcl/Tk is said to be running under Windows and the portability of the files is high. Thus it should be easy to create a dll and use the bibtool/Tcl extension on windows. Drop me a mail if you have done it. MACINTOSH ========= Tcl/Tk is said to be running under Macintosh. Thus it should be possible to port the library to this architecture. Drop me a mail if you have done it. UNIX ==== - Configure and compile bibtool in the parent directory (..). The object files must be present in this directory. - Go to the directory BibTcl. This is the directory containing this file. - Ensure that the command tclsh is present on your path. This tclsh needs to be not too old and it needs to be installed properly. - If you have wish at hand you can try the program install.tcl in this directory. This program performs the following tasks and displays the results in a window: - Run ./configure You need to give the same arguments as for the configuration of BibTool in the previous directory. Especially prefix and exec-prefix are required to be the same. This should produce the file Makefile in the current directory. - On Solaris edit the Makefile and remove '-z text' from SHLIB_LD. - Run make This should produce the shared library and a small Tcl loader which is independent of the architecture. In fact it figures out the architecture and uses the appropriate version which should be installed. - Run make install This creates a subdirectory of LIBDIR according to the OS used. This directory contains the shared library as well as the loader script. The loader script can be freely copied to any other place. The shared library must stay in this directory since the location is compiled into the loader script. - Run make clean to remove the intermediate files. This procedure can be repeated for different architectures which share the same installation directory. DOCUMENTATION ============= I have started to describe the Tcl interface in the document bibtcl.ltx which can be found in this directory. Consult this document for further descriptions. Gerd Neugebauer gerd.neugebauer@sdm.de BibTool/BibTcl/version.tex0000644000175100017510000000056412254327060014404 0ustar genegene%%******************************************************** %% %% This file is part of BibTool. %% It is distributed under the GNU General Public License. %% See the file COPYING for details. %% %% (c) 1995-2013 Gerd Neugebauer %% %% Net: gerd.neugebauer@sdm.de %% %%******************************************************** \newcommand\Year{2013} \newcommand\Version{2.56} BibTool/BibTcl/Makefile0000644000175100017510000000574010562704521013637 0ustar genegene# Generated automatically from Makefile.in by configure. # ***************************************************************************** # $Id: Makefile,v 1.1 2007-02-08 20:34:25 gene Exp $ # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 1996-2001 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # ***************************************************************************** prefix = /usr/local exec_prefix = ${prefix} LIBDIR = ${exec_prefix}/lib/BibTool CC = gcc -pipe CFLAGS = -g SHLIB_CFLAGS = -fPIC SHLIB_LD = gcc -pipe -shared SHLIB_SUFFIX = .so SHLIB_VERSION = SRC_DIR = . TCLSH = tclsh TCL_VERSION = 8.4 TCL_PREFIX = /usr TCL_INCLUDE = /usr/include RM = /bin/rm -f LATEX = latex BIBTEX = bibtex MAKEINDEX = makeindex BIBTOOLDIR = .. OFILES = $(BIBTOOLDIR)/database.o \ $(BIBTOOLDIR)/entry.o \ $(BIBTOOLDIR)/error.o \ $(BIBTOOLDIR)/expand.o \ $(BIBTOOLDIR)/init.o \ $(BIBTOOLDIR)/key.o \ $(BIBTOOLDIR)/macros.o \ $(BIBTOOLDIR)/names.o \ $(BIBTOOLDIR)/parse.o \ $(BIBTOOLDIR)/print.o \ $(BIBTOOLDIR)/pxfile.o \ $(BIBTOOLDIR)/record.o \ $(BIBTOOLDIR)/rewrite.o \ $(BIBTOOLDIR)/regex.o \ $(BIBTOOLDIR)/rsc.o \ $(BIBTOOLDIR)/s_parse.o \ $(BIBTOOLDIR)/symbols.o \ $(BIBTOOLDIR)/stack.o \ $(BIBTOOLDIR)/sbuffer.o \ $(BIBTOOLDIR)/tex_aux.o \ $(BIBTOOLDIR)/tex_read.o \ $(BIBTOOLDIR)/type.o \ $(BIBTOOLDIR)/version.o \ $(BIBTOOLDIR)/wordlist.o all: bibtool${SHLIB_SUFFIX} bibtool.tcl bibtool${SHLIB_SUFFIX}: bibtool.c $(OFILES) $(CC) -c $(CFLAGS) -I$(BIBTOOLDIR)/include -I$(TCL_INCLUDE) $(SHLIB_CFLAGS) -o bibtool.o $< $(SHLIB_LD) bibtool.o $(OFILES) -o $@ $(RM) bibtool.o bibtool.tcl: Makefile @echo "#----------------------------------------------------------" >$@ @echo "# This file is automatically created." >>$@ @echo "# Any modifications will be lost the next time it is made." >>$@ @echo "# This file is part of BibTool." >>$@ @echo "# Copyright (C) 1997-1998 Gerd Neugebauer." >>$@ @echo "set BIBTOOLDIR {$(LIBDIR)}" >>$@ @echo 'load $$BIBTOOLDIR/$$tcl_platform(os)$$tcl_platform(osVersion)/bibtool[info sharedlibextension]' >>$@ INST_DIR = `echo 'puts $(LIBDIR)/$$tcl_platform(os)$$tcl_platform(osVersion)'|$(TCLSH)` bibtcl.aux bibtcl.idx: bibtcl.tex bibtcl.ltx $(LATEX) bibtcl.ltx bibtcl.dvi: bibtcl.tex bibtcl.ltx bibtcl.bbl bibtcl.ind $(LATEX) bibtcl.ltx $(LATEX) bibtcl.ltx bibtcl.ind: bibtcl.idx $(MAKEINDEX) -s bibtool.ist bibtcl bibtcl.bbl: bibtcl.bib bibtcl.aux $(BIBTEX) bibtcl install: bibtool${SHLIB_SUFFIX} bibtool.tcl -mkdir $(INST_DIR) cp bibtool${SHLIB_SUFFIX} bibtool.tcl $(INST_DIR) clean: rm -f *.o *${SHLIB_SUFFIX} config.cache config.log config.status lib.exp distclean: clean rm -f Makefile status: @echo $(LIBDIR) BibTool/configure.in0000644000175100017510000001010612646460214013344 0ustar genegenednl *************************************************************************** dnl dnl This file is part of BibTool. dnl It is distributed under the GNU General Public License. dnl See the file COPYING for details. dnl dnl (c) 1996-2016 Gerd Neugebauer dnl dnl Net: gene@gerd-neugebauer.de dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2, or (at your option) dnl any later version. dnl dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. dnl dnl *************************************************************************** AC_REVISION($Revision: 1.10 $)dnl AC_PREREQ(2.59) dnl --------------------------------------------------------------------------- dnl Process this file with autoconf to produce a configure script. AC_INIT(sbuffer.c) dnl --------------------------------------------------------------------------- dnl Checks for programs. AC_PROG_CC AC_PROG_INSTALL AC_PROG_RANLIB dnl AC_PATH_PROGS(PERL,perl perl5.003 perl4.036 /usr/local/bin/perl) dnl AC_PATH_PROGS(TCLSH,tclsh tclsh-8.0 tclsh-8.1 tclsh-8.2 tclx,/usr/local/bin/tclsh) dnl --------------------------------------------------------------------------- dnl for regexp AC_AIX AC_ISC_POSIX AC_MINIX dnl --------------------------------------------------------------------------- dnl Checks for libraries. dnl --------------------------------------------------------------------------- dnl Checks for header files. AC_HEADER_STDC AC_STDC_HEADERS dnl --------------------------------------------------------------------------- dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T dnl --------------------------------------------------------------------------- dnl Checks for library functions. AC_FUNC_ALLOCA AC_FUNC_MEMCMP dnl --------------------------------------------------------------------------- dnl Check for headers. AC_CHECK_HEADERS(string.h) AC_CHECK_HEADERS(stdlib.h) AC_CHECK_HEADERS(time.h) AC_CHECK_FUNCS(getenv) AC_CHECK_FUNCS(strrchr) dnl --------------------------------------------------------------------------- AC_ARG_WITH(kpathsea,Use the KPATHSEA library.,,with_kpathsea=yes) if test $with_kpathsea = no; then kpathsea_dir= kpathsea_lib= kpathsea_def= else AC_MSG_CHECKING(for kpathsea library) kpathsea_dir= kpathsea_lib= kpathsea_lib_static= kpathsea_def= AC_TRY_COMPILE( [ #include #include ],[], [ kpathsea_dir=/usr/include kpathsea_lib=-lkpathsea kpathsea_def=-DHAVE_LIBKPATHSEA ], [ for cand in .. ../kpse3-2 kpse3-2 . /usr/include /usr/local/include do if test -f $cand/kpathsea/tex-file.h ; then if test -f $cand/../lib/libkpathsea.a; then kpathsea_dir=$cand kpathsea_def="-DHAVE_LIBKPATHSEA -I$cand" kpathsea_lib_static=$cand/../lib/libkpathsea.a else if test -f $cand/kpathsea/STATIC/libkpathsea.a; then kpathsea_lib_static=$cand/kpathsea/STATIC/libkpathsea.a kpathsea_dir=$cand kpathsea_def="-DHAVE_LIBKPATHSEA -I$cand" fi fi fi done ]) if test -z "$kpathsea_dir"; then AC_MSG_WARN(not found) else AC_MSG_RESULT($kpathsea_dir) fi fi AC_SUBST(kpathsea_dir)dnl AC_SUBST(kpathsea_lib)dnl AC_SUBST(kpathsea_lib_static)dnl AC_SUBST(kpathsea_def)dnl dnl --------------------------------------------------------------------------- dnl AC_CONFIG_SUBDIRS(regex-0.12) dnl --------------------------------------------------------------------------- dnl AC_CONFIG_SUBDIRS(BibTcl) AC_CONFIG_HEADER(include/bibtool/config.h:AutoConf/config.h.in regex-0.12/config.h:AutoConf/reconfig.h.in) AC_OUTPUT(makefile:AutoConf/makefile.in) BibTool/install-sh0000755000175100017510000001272110562442074013043 0ustar genegene#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # 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. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 BibTool/mkdirchain0000755000175100017510000000510510562442043013070 0ustar genegene#!/bin/sh # Make directory hierarchy. # Written by Noah Friedman # (Minor modificatons by karl@cs.umb.edu.) # Public domain. for file in ${1+"$@"} ; do oIFS="${IFS}"; IFS='/'; set - ${file}; IFS="${oIFS}" test ".${1}" = "." && shift pathcomp='' while test $# -ne 0 ; do pathcomp="${pathcomp}/${1}" shift if test ! -d "${pathcomp}"; then echo "mkdir $pathcomp" 1>&2 mkdir "${pathcomp}" || exit 1 fi done done exit 0 Date: Fri, 14 May 93 12:47:22 edt From: friedman@gnu.ai.mit.edu (Noah Friedman) To: meyering@idefix.comco.com Cc: gnu-prog-disc@gnu.ai.mit.edu Subject: Re: directory-making fragment >Hi Noah. >I'm thinking about adding this to the *utils. >Have you heard anything that would indicate I shouldn't? No, though I discovered from personal experience that this shell fragment is too long on some systems to appear on a command line. The pty buffer on some systems is very small---if you try to do "make installdirs", you get an immediate failure. Running it interactively just prints lots of C-g's. What I did for the texinfo distribution is to put the script in a separate file called `mkinstalldirs', then invoke it from the Makefile with the appropriate arguments. Here is what it looks like: #!/bin/sh # Make directory hierarchy. # Written by Noah Friedman # Public domain. umask 002 for file in ${1+"$@"} ; do oIFS="${IFS}"; IFS='/'; set - ${file}; IFS="${oIFS}" test ".${1}" = "." && shift pathcomp='' while test $# -ne 0 ; do pathcomp="${pathcomp}/${1}" shift if test ! -d "${pathcomp}"; then echo "mkdir $pathcomp" 1>&2 mkdir "${pathcomp}" fi done done # eof >On May 7, 6:18am, Noah Friedman wrote: >| The following target might be a useful thing for people to include in all >| GNU Makefiles and make the `install' target depend on it. This is what I >| did for Bison. >| >| # Make sure all installation directories, e.g. $(bindir) actually exist by >| # making them if necessary. >| installdirs: >| for file in $(bindir) $(datadir) $(libdir) $(infodir) $(mandir) ; do \ >| oIFS="$${IFS}"; IFS='/'; set - $${file}; IFS="$${oIFS}"; \ >| pathcomp=''; test ".$${1}" = "." && shift; \ >| while test $$# -ne 0 ; do \ >| pathcomp="$${pathcomp}/$${1}"; shift; \ >| if test ! -d "$${pathcomp}"; then \ >| echo "making directory $$pathcomp" 1>&2 ; \ >| mkdir "$${pathcomp}"; \ >| fi; \ >| done; \ >| done BibTool/test/lib/BUnit.pm0000644000175100017510000002034312646462401014143 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME BUnit.pm - Driver for BibTool test cases =head1 SYNOPSIS perl -MBUnit -e "exit all()" =head1 DESCRIPTION This is the test driver for unit tests of BibTool. =head1 Attributes =head1 Methods =head2 all() This method collects all files with the extension .t and executes them as test cases. =head2 suites() This method takes a glob pattern as argument and executes all matching files as test cases. =head2 run() This method defines a single test case. =head1 AUTHOR Gerd Neugebauer =head1 BUGS none =cut #------------------------------------------------------------------------------ package BUnit; use strict; use Exporter; use base qw(Exporter); our @EXPORT = qw(all summary run); our @EXPORT_OK = qw(); use Cwd; use FileHandle; use Time::HiRes qw/gettimeofday/; use constant TEST_RSC =>'_test.rsc'; use constant TEST_BIB =>'_test.bib'; #------------------------------------------------------------------------------ # Variable: $verbose # Description: # our $verbose = 1; #------------------------------------------------------------------------------ # Variable: $VERSION # Description: # our $VERSION = '1.17'; #------------------------------------------------------------------------------ # Variable: $BIBTOOL # Description: # our $BIBTOOL = $ENV{'BIBTOOL_PRG'} || '../bibtool'; #------------------------------------------------------------------------------ # Variable: $name_prefix # Description: # our $name_prefix = ''; #------------------------------------------------------------------------------ # Variable: %summary # Description: # our %summary = (); #------------------------------------------------------------------------------ # Variable: %id # Description: # our %names = (); our ($success, $ignored, $failure); #------------------------------------------------------------------------------ # Function: out # sub out (@) { print @_ if $verbose; } #------------------------------------------------------------------------------ # Function: run # sub run { my %a = @_; my $name = $name_prefix . $a{name}; my $prepare = $a{prepare}; if (defined $names{$name}) { print STDERR "*** Warning: Multiple test cases named $name\n"; } else { $names{$name} = 1; } &{$prepare}($name) if defined $prepare; local $_ = ''; $_ = '.' x (40-length($name)) if length($name) < 40; out " ",$name,$_; if ($a{ignore}) { $ignored++; out "ignored $a{ignore}\n"; return 1; } my $out = "$name.out"; my $err = "$name.err"; my $null = "/dev/null"; my $args = ($a{args} || ''); my $rsc = store_file(TEST_RSC, $a{resource}, "-r ".TEST_RSC); my $bib = store_file(TEST_BIB, $a{bib}, TEST_BIB) if $a{bib}; $bib = '' if not $bib; print "\n$BIBTOOL $args $rsc $bib <$null 1>$out 2>$err\n" if $a{debug}; `$BIBTOOL $args $rsc $bib <$null 1>$out 2>$err`; if ( run_check($name, $a{check}) + check($a{expected_out}, $out, 'out', $a{fct_out}) + check($a{expected_err}, $err, 'err', $a{fct_err}) ) { $failure++; out "\n\t\t\t\t fail\n" } else { $success++; out "ok\n" } unlink(TEST_RSC) if -e TEST_RSC; unlink(TEST_BIB) if -e TEST_BIB; my $post = $a{post}; &{$post}($name) if defined $post; return 1; } #------------------------------------------------------------------------------ # Function: store_file # sub store_file { my ($file, $content, $ret) = @_; return '' if not defined $content; local $_ = new FileHandle($file,'w') || die "$file: $!\n"; print $_ $content; $_->close(); return $ret; } #------------------------------------------------------------------------------ # Function: run_check # sub run_check { my ($name, $check) = @_; return 0 if not defined $check; return &{$check}($name); } #------------------------------------------------------------------------------ # Function: check # sub check { my ($expected, $file, $type, $fct) = @_; if (defined $expected) { my $fd = new FileHandle($file,'r') || die("$file: $!\n"); local $/ = undef; local $_ = <$fd>; $fd->close(); $_ = &$fct($_) if defined $fct; if ($_ ne $expected) { my $fd = new FileHandle("$file-expected",'w') || die("$file-expected: $!\n"); print $fd $expected; $fd->close(); print STDERR "\n***\tSee actual $type in $file; " if $verbose; return 1; } } unlink $file; return 0; } #------------------------------------------------------------------------------ # Function: all # sub all { suites (glob '*.t */*.t') } #------------------------------------------------------------------------------ # Function: suites # sub suites { local $_; my @a = sort(@_); my $len = 6; my $suite; $ENV{HOME} = getcwd; die "*** '$BIBTOOL' executable not found\n" if not -x $BIBTOOL; die "*** Current dircetory is not writable\n" if not -w '.'; die "*** .bibtoolrsc exists in current directory. Aborted\n" if -e ".bibtoolrsc"; die "*** .bibtoolrsc exists in this directory. Aborted \n" if -e "$ENV{HOME}/.bibtoolrsc"; foreach $_ (@a) { my $l = length($_); $len = $l if $l > $len; } my $time = gettimeofday; foreach $_ (@a) { $success = 0; $ignored = 0; $failure = 0; $suite = $_; $suite =~ s/\.t$//; my $ret = do "$_"; unless($ret) { if ($@) { warn "couldn't parse $_: $@\n" } elsif(not defined $ret) { warn "couldn't do $_: $!\n" } else { warn "couldn't run $_\n" } $failure++; } $summary{$_} = [$success, $ignored, $failure]; } $success = 0; $ignored = 0; $failure = 0; printf("\n%-${len}s success ignored failure\n", '') if $verbose; foreach $suite (@a) { $_ = $suite; s/\.t$//; printf("%-${len}s%7d %7d %7d\n", $_, $summary{$suite}[0], $summary{$suite}[1], $summary{$suite}[2]) if $verbose; $success += $summary{$suite}[0]; $ignored += $summary{$suite}[1]; $failure += $summary{$suite}[2];; } $time = gettimeofday - $time; my $no = $success + $failure; if ($no == 0) { $_ = 100 } else { $_ = 100. * $success/$no; } printf("%s\n%-${len}s%7d %7d %7d\nSuccess rate: %3.2f%%\n", ('_' x ($len+40)), 'TOTAL', $success, $ignored, $failure, $_) if $verbose; printf("Run time: %1.2fs\tAverage: %1.0fms\n\n", $time, $time*1000/$no) if $verbose; return $failure; } #------------------------------------------------------------------------------ # Function: get_library_path # sub get_library_path { my $err = '_lib.err'; `$BIBTOOL -h 2>$err`; my $library_path; local $_; my $fd = new FileHandle($err) || die "$err: $!\n"; while(<$fd>) { $library_path = $1 if m/^Library path: (.*)/; } $fd->close(); unlink($err); return $library_path; } #------------------------------------------------------------------------------ # Function: get_configuration_options # sub get_configuration_options { my $err = '_lib.err'; `$BIBTOOL -h 2>$err`; my $options; local $_; my $fd = new FileHandle($err) || die "$err: $!\n"; while(<$fd>) { $options = $1 if m/^Special configuration options: (.*)/; } $fd->close(); unlink($err); return $options; } #------------------------------------------------------------------------------ 1; # BibTool/test/makefile0000644000175100017510000000663312646462461013532 0ustar genegene# ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= # # This is the makefile to run the test suite for BibTool. It should # work at least for Unix-like systems with GNUmake and bash. # For instance Linux and Windows with cygwin fulfill this pre-condition. # # Note that portability hasn't been an issue for this makefile yet. # # ------------------------------------------------------- # EXT is the optional extension of the final executable. # Various Operating Systems have their own ideas about # that. # EXT = # ----------------------------------------------------------------------------- BIBTOOL_PRG = ../bibtool$(EXT) PERL = perl DIR_SEP =/ CPATH = ..${DIR_SEP} CFILES = ${CPATH}main.c \ ${CPATH}crossref.c \ ${CPATH}database.c \ ${CPATH}entry.c \ ${CPATH}error.c \ ${CPATH}expand.c \ ${CPATH}init.c \ ${CPATH}key.c \ ${CPATH}macros.c \ ${CPATH}names.c \ ${CPATH}parse.c \ ${CPATH}print.c \ ${CPATH}pxfile.c \ ${CPATH}record.c \ ${CPATH}rewrite.c \ ${CPATH}rsc.c \ ${CPATH}s_parse.c \ ${CPATH}symbols.c \ ${CPATH}stack.c \ ${CPATH}sbuffer.c \ ${CPATH}tex_aux.c \ ${CPATH}tex_read.c \ ${CPATH}type.c \ ${CPATH}version.c \ ${CPATH}wordlist.c HPATH = ${CPATH}include${DIR_SEP}bibtool${DIR_SEP} HFILES = ${CPATH}config.h \ ${HPATH}crossref.h \ ${HPATH}database.h \ ${HPATH}bibtool.h \ ${HPATH}config.h \ ${HPATH}entry.h \ ${HPATH}error.h \ ${HPATH}expand.h \ ${HPATH}general.h \ ${HPATH}init.h \ ${HPATH}key.h \ ${HPATH}keynode.h \ ${HPATH}macros.h \ ${HPATH}names.h \ ${HPATH}parse.h \ ${HPATH}print.h \ ${HPATH}pxfile.h \ ${HPATH}regex.h \ ${HPATH}record.h \ ${HPATH}resource.h \ ${HPATH}rewrite.h \ ${HPATH}rsc.h \ ${HPATH}s_parse.h \ ${HPATH}sbuffer.h \ ${HPATH}stack.h \ ${HPATH}symbols.h \ ${HPATH}tex_aux.h \ ${HPATH}tex_read.h \ ${HPATH}type.h \ ${HPATH}version.h \ ${HPATH}wordlist.h default check all: $(BIBTOOL_PRG) $(SUITES) @BIBTOOL_PRG=$(BIBTOOL_PRG) ${PERL} -Ilib -MBUnit -e "exit all()" ../bibtool$(EXT): $(CFILES) $(HFILES) (cd ..; make) clean: ${RM} *.log *.err *.???-expected *.out *~ *.bak distclean: clean # ----------------------------------------------------------------------------- .SUFFIXES: .t .test $(SUFFIXES) .t.test: $(BIBTOOL_PRG) @BIBTOOL_PRG=$(BIBTOOL_PRG) $(PERL) -Ilib $< # BibTool/test/bib/x1.bib0000644000175100017510000000013112501326601013540 0ustar genegene @Manual{BibTool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } BibTool/test/bib/xampl.bib0000644000175100017510000002320311662215505014345 0ustar genegene@preamble{ "\newcommand{\noopsort}[1]{} " # "\newcommand{\printfirst}[2]{#1} " # "\newcommand{\singleletter}[1]{#1} " # "\newcommand{\switchargs}[2]{#2#1} " } @ARTICLE{article-minimal, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\mbox{G-Animal's} Journal}, year = 1986, } @ARTICLE{article-full, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, pages = "73+", month = jul, note = "This is a full ARTICLE entry", } The KEY field is here to override the KEY field in the journal being cross referenced (so is the NOTE field, in addition to its imparting information). @ARTICLE{article-crossref, crossref = {WHOLE-JOURNAL}, key = "", author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, pages = "73+", note = "This is a cross-referencing ARTICLE entry", } @ARTICLE{whole-journal, key = "GAJ", journal = {\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, month = jul, note = {The entire issue is devoted to gnats and gnus (this entry is a cross-referenced ARTICLE (journal))}, } @INBOOK{inbook-minimal, author = "Donald E. Knuth", title = "Fundamental Algorithms", publisher = "Addison-Wesley", year = "{\noopsort{1973b}}1973", chapter = "1.2", } @INBOOK{inbook-full, author = "Donald E. Knuth", title = "Fundamental Algorithms", volume = 1, series = "The Art of Computer Programming", publisher = "Addison-Wesley", address = "Reading, Massachusetts", edition = "Second", month = "10~" # jan, year = "{\noopsort{1973b}}1973", type = "Section", chapter = "1.2", pages = "10--119", note = "This is a full INBOOK entry", } @INBOOK{inbook-crossref, crossref = "whole-set", title = "Fundamental Algorithms", volume = 1, series = "The Art of Computer Programming", edition = "Second", year = "{\noopsort{1973b}}1973", type = "Section", chapter = "1.2", note = "This is a cross-referencing INBOOK entry", } @BOOK{book-minimal, author = "Donald E. Knuth", title = "Seminumerical Algorithms", publisher = "Addison-Wesley", year = "{\noopsort{1973c}}1981", } @BOOK{book-full, author = "Donald E. Knuth", title = "Seminumerical Algorithms", volume = 2, series = "The Art of Computer Programming", publisher = "Addison-Wesley", address = "Reading, Massachusetts", edition = "Second", month = "10~" # jan, year = "{\noopsort{1973c}}1981", note = "This is a full BOOK entry", } @BOOK{book-crossref, crossref = "whole-set", title = "Seminumerical Algorithms", volume = 2, series = "The Art of Computer Programming", edition = "Second", year = "{\noopsort{1973c}}1981", note = "This is a cross-referencing BOOK entry", } @BOOK{whole-set, author = "Donald E. Knuth", publisher = "Addison-Wesley", title = "The Art of Computer Programming", series = "Four volumes", year = "{\noopsort{1973a}}{\switchargs{--90}{1968}}", note = "Seven volumes planned (this is a cross-referenced set of BOOKs)", } @BOOKLET{booklet-minimal, key = "Kn{\printfirst{v}{1987}}", title = "The Programming of Computer Art", } @BOOKLET{booklet-full, author = "Jill C. Knvth", title = "The Programming of Computer Art", howpublished = "Vernier Art Center", address = "Stanford, California", month = feb, year = 1988, note = "This is a full BOOKLET entry", } @INCOLLECTION{incollection-minimal, author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", booktitle = "High Speed Computer and Algorithm Organization", publisher = "Academic Press", year = 1977, } @INCOLLECTION{incollection-full, author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", booktitle = "High Speed Computer and Algorithm Organization", number = 23, series = "Fast Computers", chapter = 3, type = "Part", pages = "179--183", publisher = "Academic Press", address = "New York", edition = "Third", month = sep, year = 1977, note = "This is a full INCOLLECTION entry", } @INCOLLECTION{incollection-crossref, crossref = "whole-collection", author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", pages = "179--183", note = "This is a cross-referencing INCOLLECTION entry", } @BOOK{whole-collection, editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", title = "High Speed Computer and Algorithm Organization", booktitle = "High Speed Computer and Algorithm Organization", number = 23, series = "Fast Computers", publisher = "Academic Press", address = "New York", edition = "Third", month = sep, year = 1977, note = "This is a cross-referenced BOOK (collection) entry", } @MANUAL{manual-minimal, key = "Manmaker", title = "The Definitive Computer Manual", } @MANUAL{manual-full, author = "Larry Manmaker", title = "The Definitive Computer Manual", organization = "Chips-R-Us", address = "Silicon Valley", edition = "Silver", month = apr # "-" # may, year = 1986, note = "This is a full MANUAL entry", } @MASTERSTHESIS{mastersthesis-minimal, author = "{\'{E}}douard Masterly", title = "Mastering Thesis Writing", school = "Stanford University", year = 1988, } @MASTERSTHESIS{mastersthesis-full, author = "{\'{E}}douard Masterly", title = "Mastering Thesis Writing", school = "Stanford University", type = "Master's project", address = "English Department", month = jun # "-" # aug, year = 1988, note = "This is a full MASTERSTHESIS entry", } @MISC{misc-minimal, key = "Missilany", note = "This is a minimal MISC entry", } @MISC{misc-full, author = "Joe-Bob Missilany", title = "Handing out random pamphlets in airports", howpublished = "Handed out at O'Hare", month = oct, year = 1984, note = "This is a full MISC entry", } @STRING{STOC-key = "OX{\singleletter{stoc}}"} @STRING{ACM = "The OX Association for Computing Machinery"} @STRING{STOC = " Symposium on the Theory of Computing"} @INPROCEEDINGS{inproceedings-minimal, author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", booktitle = "Proc. Fifteenth Annual ACM" # STOC, year = 1983, } @INPROCEEDINGS{inproceedings-full, author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", editor = "Wizard V. Oz and Mihalis Yannakakis", booktitle = "Proc. Fifteenth Annual ACM" # STOC, number = 17, series = "All ACM Conferences", pages = "133--139", month = mar, year = 1983, address = "Boston", organization = ACM, publisher = "Academic Press", note = "This is a full INPROCEDINGS entry", } @INPROCEEDINGS{inproceedings-crossref, crossref = "whole-proceedings", author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", organization = "", pages = "133--139", note = "This is a cross-referencing INPROCEEDINGS entry", } @PROCEEDINGS{proceedings-minimal, key = STOC-key, title = "Proc. Fifteenth Annual" # STOC, year = 1983, } @PROCEEDINGS{proceedings-full, editor = "Wizard V. Oz and Mihalis Yannakakis", title = "Proc. Fifteenth Annual" # STOC, number = 17, series = "All ACM Conferences", month = mar, year = 1983, address = "Boston", organization = ACM, publisher = "Academic Press", note = "This is a full PROCEEDINGS entry", } @PROCEEDINGS{whole-proceedings, key = STOC-key, organization = ACM, title = "Proc. Fifteenth Annual" # STOC, address = "Boston", year = 1983, booktitle = "Proc. Fifteenth Annual ACM" # STOC, note = "This is a cross-referenced PROCEEDINGS", } @PHDTHESIS{phdthesis-minimal, author = "F. Phidias Phony-Baloney", title = "Fighting Fire with Fire: Festooning {F}rench Phrases", school = "Fanstord University", year = 1988, } @PHDTHESIS{phdthesis-full, author = "F. Phidias Phony-Baloney", title = "Fighting Fire with Fire: Festooning {F}rench Phrases", school = "Fanstord University", type = "{PhD} Dissertation", address = "Department of French", month = jun # "-" # aug, year = 1988, note = "This is a full PHDTHESIS entry", } @TECHREPORT{techreport-minimal, author = "Tom Terrific", title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm", institution = "Fanstord University", year = 1988, } @TECHREPORT{techreport-full, author = "Tom T{\'{e}}rrific", title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm", institution = "Fanstord University", type = "Wishful Research Result", number = "7", address = "Computer Science Department, Fanstord, California", month = oct, year = 1988, note = "This is a full TECHREPORT entry", } @UNPUBLISHED{unpublished-minimal, author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot", title = "Lower Bounds for Wishful Research Results", note = "Talk at Fanstord University (this is a minimal UNPUBLISHED entry)", } @UNPUBLISHED{unpublished-full, author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot", title = "Lower Bounds for Wishful Research Results", month = nov # ", " # dec, year = 1988, note = "Talk at Fanstord University (this is a full UNPUBLISHED entry)", } @MISC{random-note-crossref, key = {Volume-2}, note = "Volume~2 is listed under Knuth \cite{book-full}" } BibTool/test/bib/xampl_s.bib0000644000175100017510000000273411662215505014675 0ustar genegene@ARTICLE{article-minimal, title=""} @ARTICLE{article-full, title=""} @ARTICLE{article-crossref, title=""} @ARTICLE{whole-journal, title=""} @INBOOK{inbook-minimal, title=""} @INBOOK{inbook-full, title=""} @INBOOK{inbook-crossref, title=""} @BOOK{book-minimal, title=""} @BOOK{book-full, title=""} @BOOK{book-crossref, title=""} @BOOK{whole-set, title=""} @BOOKLET{booklet-minimal, title=""} @BOOKLET{booklet-full, title=""} @INCOLLECTION{incollection-minimal, title=""} @INCOLLECTION{incollection-full, title=""} @INCOLLECTION{incollection-crossref, title=""} @BOOK{whole-collection, title=""} @MANUAL{manual-minimal, title=""} @MANUAL{manual-full, title=""} @MASTERSTHESIS{mastersthesis-minimal, title=""} @MASTERSTHESIS{mastersthesis-full, title=""} @MISC{misc-minimal, title=""} @MISC{misc-full, title=""} @STRING{STOC-key = "OX"} @STRING{ACM = "The OX Association for Computing Machinery"} @STRING{STOC = " Symposium on the Theory of Computing"} @INPROCEEDINGS{inproceedings-minimal, title=""} @INPROCEEDINGS{inproceedings-full, title=""} @INPROCEEDINGS{inproceedings-crossref, title=""} @PROCEEDINGS{proceedings-minimal, title=""} @PROCEEDINGS{proceedings-full, title=""} @PROCEEDINGS{whole-proceedings, title=""} @PHDTHESIS{phdthesis-minimal, title=""} @PHDTHESIS{phdthesis-full, title=""} @TECHREPORT{techreport-minimal, title=""} @TECHREPORT{techreport-full, title=""} @UNPUBLISHED{unpublished-minimal, title=""} @UNPUBLISHED{unpublished-full, title=""} @MISC{random-note-crossref, title=""} BibTool/test/add_field.t0000644000175100017510000000526012646462064014104 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME add_field.t - Test suite for BibTool add.field. =head1 SYNOPSIS add_field.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'add_field_1', args => 'bib/x1.bib', resource => 'add.field={xyzzy="abc"}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015, xyzzy = {abc} } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'add_field_2', args => 'bib/x1.bib', resource => 'add.field={xyzzy={abc}}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015, xyzzy = {abc} } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'add_field_3', args => 'bib/x1.bib', resource => 'add.field={xyzzy=abc}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015, xyzzy = {abc} } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/apply_alias.t0000644000175100017510000000442312646462052014504 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME apply_alias.t - Test suite for BibTool apply.alias. =head1 SYNOPSIS apply_alias.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'apply_alias_0', bib => <<__EOF__, \@article{xyzzy, a=987} \@alias{qqq=xyzzy} __EOF__ resource => 'apply.alias=off', expected_out => <<__EOF__, \@Article{ xyzzy, a = 987 } \@ALIAS{qqq = xyzzy } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'apply_alias_1', bib => <<__EOF__, \@article{xyzzy, a=987} \@alias{qqq=xyzzy} __EOF__ resource => 'apply.alias=on', expected_out => <<__EOF__, \@Article{ xyzzy, a = 987 } \@Article{ qqq, a = 987 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/apply_include.t0000644000175100017510000000503112646462076015040 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME apply_include.t - Test suite for BibTool apply.include. =head1 SYNOPSIS apply_include.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'apply_include_0', bib => <<__EOF__, \@include{xyzzy} __EOF__ resource => 'apply.include=off', expected_out => <<__EOF__, \@INCLUDE{xyzzy} __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'apply_include_1', bib => <<__EOF__, \@include{xyzzy} __EOF__ resource => 'apply.include=on', expected_out => '', expected_err => "\n*** BibTool ERROR: File not found: xyzzy\n" ); #------------------------------------------------------------------------------ BUnit::run(name => 'apply_include_2', bib => <<__EOF__, \@include{bib/x1.bib} __EOF__ resource => 'apply.include=on', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/apply_modify.t0000644000175100017510000000577312646462107014714 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME apply_modify.t - Test suite for BibTool apply.modify. =head1 SYNOPSIS apply_modify.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'apply_modify_0', bib => <<__EOF__, \@article{xyzzy, a=987} \@modify{xyzzy, a=123} __EOF__ resource => 'apply.modify=off', expected_out => <<__EOF__, \@Article{ xyzzy, a = 987 } \@MODIFY{ xyzzy, a = 123 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'apply_modify_1', bib => <<__EOF__, \@article{xyzzy, a=987} \@modify{xyzzy, a=123} __EOF__ resource => 'apply.modify=on', expected_out => <<__EOF__, \@Article{ xyzzy, a = 123 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'apply_modify_2', bib => <<__EOF__, \@article{xyzzy, a=987} \@modify{xyzzy, b=123} __EOF__ resource => 'apply.modify=on', expected_out => <<__EOF__, \@Article{ xyzzy, a = 987, b = 123 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'apply_modify_3', bib => <<__EOF__, \@article{xyzzy, a=987} \@alias{qqq=xyzzy} \@modify{xyzzy, a=123} __EOF__ resource => 'apply.modify=on apply.alias=on', expected_out => <<__EOF__, \@Article{ xyzzy, a = 123 } \@Article{ qqq, a = 987 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/bibtex_env_name.t0000644000175100017510000000477212646462122015340 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME bibtex_env_name.t - Test suite for BibTool bibtex.env.name. =head1 SYNOPSIS bibtex_env_name.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'bibtex_env_name_0', args => 'x1', expected_err => "\n*** BibTool WARNING: File x1 not found.\n" ); $ENV{BIBINPUTS} = "bib"; #------------------------------------------------------------------------------ BUnit::run(name => 'bibtex_env_name_1', args => 'x1', expected_err => "" ); delete $ENV{BIBINPUTS}; my $use_kpathsea = undef; $use_kpathsea = "since only applicable without kpathsea" if BUnit::get_configuration_options() =~ m/kpathsea/; $ENV{BIBTOOLINPUTS} = "bib"; #------------------------------------------------------------------------------ BUnit::run(name => 'bibtex_env_name_2', ignore => $use_kpathsea, resource => "bibtex.env.name={BIBTOOLINPUTS}", args => 'x1', expected_err => "" ); delete $ENV{BIBTOOLINPUTS}; 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/bibtex_search_path.t0000644000175100017510000000377412646462134016035 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME bibtex_search_path.t - Test suite for BibTool bibtex.search.path. =head1 SYNOPSIS bibtex_search_path.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; my $use_kpathsea = undef; $use_kpathsea = "since only applicable without kpathsea" if BUnit::get_configuration_options() =~ m/kpathsea/; #------------------------------------------------------------------------------ BUnit::run(name => 'bibtex_search_path_1', ignore => $use_kpathsea, resource => "bibtex.search.path={.:bib}", args => 'x1.bib', expected_err => "" ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/bibtool.t0000644000175100017510000001000012646462170013625 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2015-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME bibtool.t - Test suite for BibTool. =head1 SYNOPSIS bibtool.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'bibtool_1', bib => <<__EOF__, \@Manual{BibTool, title = {BibTool}, author = "Gerd "#"Neugebauer", year = "x" # "x" # "x" } __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = "Gerd " # "Neugebauer", year = "x" # "x" # "x" } __EOF__ expected_err => "" ); #------------------------------------------------------------------------------ BUnit::run(name => 'bibtool_2', bib => <<__EOF__, \@Manual{BibTool, title = {BibTool}, author = "Gerd Neugebauer", year = "x" # may # {x} #"x" } __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = "Gerd Neugebauer", year = "x" # may # {x} # "x" } __EOF__ expected_err => "" ); #------------------------------------------------------------------------------ BUnit::run(name => 'bibtool_special_underscore', bib => <<__EOF__, \@Manual{BibTool, _title = {BibTool}, author = "Gerd Neugebauer", year = "x" } __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, _title = {BibTool}, author = "Gerd Neugebauer", year = "x" } __EOF__ expected_err => <<__EOF__ _title = {BibTool}, ___^ *** BibTool WARNING: (line 2 in ./_test.bib): Symbol does not start with a letter __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'bibtool_special_dollar', bib => <<__EOF__, \@Manual{BibTool, \$title = {BibTool}, author = "Gerd Neugebauer", year = "x" } __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, \$title = {BibTool}, author = "Gerd Neugebauer", year = "x" } __EOF__ expected_err => <<__EOF__ \$title = {BibTool}, ___^ *** BibTool WARNING: (line 2 in ./_test.bib): Symbol does not start with a letter __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'bibtool_special_exclamation', bib => <<__EOF__, \@Manual{BibTool, !title = {BibTool}, author = "Gerd Neugebauer", year = "x" } __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, !title = {BibTool}, author = "Gerd Neugebauer", year = "x" } __EOF__ expected_err => <<__EOF__ !title = {BibTool}, ___^ *** BibTool WARNING: (line 2 in ./_test.bib): Symbol does not start with a letter __EOF__ ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/bibtoolrsc.t0000644000175100017510000000550012646462156014352 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME bibtoolrsc.t - Test suite for BibTool .bibtoolrsc. =head1 SYNOPSIS bibtoolrsc.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => '_bibtoolrsc_1', ignore => (-e ".bibtoolrsc"), prepare => sub { BUnit::store_file('.bibtoolrsc','print{Done that}'); }, check => sub { unlink('.bibtoolrsc'); return 0; }, expected_err => "Done that\n" ); #------------------------------------------------------------------------------ BUnit::run(name => '_bibtoolrsc_2', ignore => (-e "$ENV{HOME}/.bibtoolrsc"), prepare => sub { BUnit::store_file("$ENV{HOME}/.bibtoolrsc",'print{Done that too}'); }, check => sub { unlink("$ENV{HOME}/.bibtoolrsc"); return 0; }, expected_err => "Done that too\n" ); #------------------------------------------------------------------------------ BUnit::run(name => '_bibtoolrsc_3', ignore => (-e ".bibtoolrsc" or -e "$ENV{HOME}/.bibtoolrsc"), prepare => sub { BUnit::store_file(".bibtoolrsc",'print{Been there}'); BUnit::store_file("$ENV{HOME}/.bibtoolrsc",'print{Done that}'); }, check => sub { unlink("$ENV{HOME}/.bibtoolrsc"); unlink('.bibtoolrsc'); return 0; }, expected_err => "Done that\n" ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/check_rule.t0000644000175100017510000000620112646462205014306 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME check_rule.t - Test suite for BibTool check.rule. =head1 SYNOPSIS check_rule.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'check_rule_1', resource => <<__EOF__, check.rule { year "^[\\"{]1[89][0-9][0-9][\\"}]\$" } check.rule { year "^[\\"{][0-9][0-9][\\"}]\$" } check.rule { year "" "\\@ \\\$: Year has to be a suitable number"} __EOF__ bib => <<__EOF__, \@Manual{BibTool, title = {BibTool}, author = {Gerd Neugebauer}, year = "2011" } __EOF__ expected_err => '*** BibTool: Manual bibtool: Year has to be a suitable number' ); #------------------------------------------------------------------------------ BUnit::run(name => 'check_rule_2', resource => <<__EOF__, check.rule { year "^[\\"{]1[89][0-9][0-9][\\"}]\$" } check.rule { year "^[\\"{][0-9][0-9][\\"}]\$" } check.rule { year "" "\\@ \\\$: Year has to be a suitable number"} __EOF__ bib => <<__EOF__, \@Manual{BibTool, title = {BibTool}, author = {Gerd Neugebauer}, year = "1987" } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'check_rule_3', resource => <<__EOF__, check.rule { year "^[\\"{]1[89][0-9][0-9][\\"}]\$" } check.rule { year "^[\\"{][0-9][0-9][\\"}]\$" } check.rule { year "" "\\@ \\\$: Year has to be a suitable number"} __EOF__ bib => <<__EOF__, \@Manual{BibTool, title = {BibTool}, author = {Gerd Neugebauer}, year = "xxx" } __EOF__ expected_err => '*** BibTool: Manual bibtool: Year has to be a suitable number' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/clear_ignored_words.t0000644000175100017510000000414612646462215016224 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME clear_ignored_words.t - Test suite for BibTool clear.ignored.words. =head1 SYNOPSIS clear_ignored_words.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'clear_ignored_words_1', resource => <<__EOF__, clear.ignored.words{} key.format=short __EOF__ bib => <<__EOF__, \@Manual{ bibtool, title = {The BibTool Manual}, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@Manual{ neugebauer:the, title = {The BibTool Manual}, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/count_all.t0000644000175100017510000001426412646462224014173 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME count_used.t - Test suite for BibTool count.used. =head1 SYNOPSIS count_used.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'count_all_1', args => '--count.all=on bib/x1', expected_err => <<__EOF__); --- STRING 0 read 0 written --- PREAMBLE 0 read 0 written --- COMMENT 0 read 0 written --- ALIAS 0 read 0 written --- MODIFY 0 read 0 written --- INCLUDE 0 read 0 written --- Article 0 read 0 written --- Book 0 read 0 written --- Booklet 0 read 0 written --- Conference 0 read 0 written --- InBook 0 read 0 written --- InCollection 0 read 0 written --- InProceedings 0 read 0 written --- Manual 1 read 1 written --- MastersThesis 0 read 0 written --- Misc 0 read 0 written --- PhDThesis 0 read 0 written --- Proceedings 0 read 0 written --- TechReport 0 read 0 written --- Unpublished 0 read 0 written __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'count_all_2', args => '--count.all=on bib/xampl.bib', expected_err => <<__EOF__); *** BibTool WARNING: (line 29 in ./bib/xampl.bib): 125 non-space characters ignored. --- STRING 3 read 3 written --- PREAMBLE 1 read 1 written --- COMMENT 0 read 0 written --- ALIAS 0 read 0 written --- MODIFY 0 read 0 written --- INCLUDE 0 read 0 written --- Article 4 read 4 written --- Book 5 read 5 written --- Booklet 2 read 2 written --- Conference 0 read 0 written --- InBook 3 read 3 written --- InCollection 3 read 3 written --- InProceedings 3 read 3 written --- Manual 2 read 2 written --- MastersThesis 2 read 2 written --- Misc 3 read 3 written --- PhDThesis 2 read 2 written --- Proceedings 3 read 3 written --- TechReport 2 read 2 written --- Unpublished 2 read 2 written __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_hash_1', args => '-# bib/x1', expected_err => <<__EOF__); --- STRING 0 read 0 written --- PREAMBLE 0 read 0 written --- COMMENT 0 read 0 written --- ALIAS 0 read 0 written --- MODIFY 0 read 0 written --- INCLUDE 0 read 0 written --- Article 0 read 0 written --- Book 0 read 0 written --- Booklet 0 read 0 written --- Conference 0 read 0 written --- InBook 0 read 0 written --- InCollection 0 read 0 written --- InProceedings 0 read 0 written --- Manual 1 read 1 written --- MastersThesis 0 read 0 written --- Misc 0 read 0 written --- PhDThesis 0 read 0 written --- Proceedings 0 read 0 written --- TechReport 0 read 0 written --- Unpublished 0 read 0 written __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_hash_2', args => '-# bib/xampl.bib', expected_err => <<__EOF__); *** BibTool WARNING: (line 29 in ./bib/xampl.bib): 125 non-space characters ignored. --- STRING 3 read 3 written --- PREAMBLE 1 read 1 written --- COMMENT 0 read 0 written --- ALIAS 0 read 0 written --- MODIFY 0 read 0 written --- INCLUDE 0 read 0 written --- Article 4 read 4 written --- Book 5 read 5 written --- Booklet 2 read 2 written --- Conference 0 read 0 written --- InBook 3 read 3 written --- InCollection 3 read 3 written --- InProceedings 3 read 3 written --- Manual 2 read 2 written --- MastersThesis 2 read 2 written --- Misc 3 read 3 written --- PhDThesis 2 read 2 written --- Proceedings 3 read 3 written --- TechReport 2 read 2 written --- Unpublished 2 read 2 written __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/count_used.t0000644000175100017510000000622112646462234014356 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME count_used.t - Test suite for BibTool count.used. =head1 SYNOPSIS count_used.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'count_used_1', args => '-- count.used=on bib/x1', expected_err => "\n--- Manual 1 read 1 written\n"); #------------------------------------------------------------------------------ BUnit::run(name => 'count_used_2', args => '-- count.used=off bib/x1', expected_err => ''); #------------------------------------------------------------------------------ BUnit::run(name => '_at_1', args => '-@ bib/x1', expected_err => "\n--- Manual 1 read 1 written\n"); #------------------------------------------------------------------------------ BUnit::run(name => '_at_2', args => '-@ bib/xampl', expected_err => <<__EOF__); *** BibTool WARNING: (line 29 in ./bib/xampl.bib): 125 non-space characters ignored. --- STRING 3 read 3 written --- PREAMBLE 1 read 1 written --- Article 4 read 4 written --- Book 5 read 5 written --- Booklet 2 read 2 written --- InBook 3 read 3 written --- InCollection 3 read 3 written --- InProceedings 3 read 3 written --- Manual 2 read 2 written --- MastersThesis 2 read 2 written --- Misc 3 read 3 written --- PhDThesis 2 read 2 written --- Proceedings 3 read 3 written --- TechReport 2 read 2 written --- Unpublished 2 read 2 written __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/default_key.t0000644000175100017510000000471412646462246014512 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME default_key.t - Test suite for BibTool default.key. =head1 SYNOPSIS default_key.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'default_key_0', args => '-f short', bib => <<__EOF__, \@Manual{ bibtool, itle = {BibTool}, uthor = {Gerd Neugebauer}, ear = 2011 } __EOF__ expected_out => <<__EOF__, \@Manual{ **key*, itle = {BibTool}, uthor = {Gerd Neugebauer}, ear = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'default_key_1', args => '-- default.key=on -f short', bib => <<__EOF__, \@Manual{ bibtool, itle = {BibTool}, uthor = {Gerd Neugebauer}, ear = 2011 } __EOF__ expected_out => <<__EOF__, \@Manual{ on, itle = {BibTool}, uthor = {Gerd Neugebauer}, ear = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/delete_field.t0000644000175100017510000000436212646462256014623 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME delete_field.t - Test suite for BibTool delete.field. =head1 SYNOPSIS delete_field.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'delete_field_1', args => 'bib/x1.bib', resource => 'delete.field={xyzzy}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'delete_field_2', args => 'bib/x1.bib', resource => 'delete.field={year}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer} } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/expand_macros.t0000644000175100017510000000517012646462265015037 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME expand_macros.t - Test suite for BibTool expand.macros. =head1 SYNOPSIS expand_macros.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'expand_macros_1', args => '-- expand.macros=on', bib => <<__EOF__, \@String{BT ="BibTool"} \@String{TeX ="\\TeX"} \@Manual{BibTool, title = BT, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = {2011} } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'expand_macros_2', args => '-- expand.macros=on', bib => <<__EOF__, \@String{BT ="BibTool"} \@String{TeX ="\\TeX"} \@Manual{BibTool, title = {The } # BT # " Manual", author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, title = {The BibTool Manual}, author = {Gerd Neugebauer}, year = {2011} } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/extract_file.t0000644000175100017510000001030412646462275014661 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME extract_file.t - Test suite for BibTool extract.file. =head1 SYNOPSIS extract_file.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => '_x_1', args => '-x xyzzy', expected_out => '', expected_err => <<__EOF__, *** BibTool ERROR: aux file xyzzy not found. __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => '_x_2', args => '-x _xyzzy.aux', prepare => sub { my $fd = new FileHandle("_xyzzy.aux",'w') || die "_xyzzy.aux: $!\n"; print $fd <<__EOF__; \\citation{whole-collection} \\bibstyle{alpha} \\bibdata{bib/xampl_s.bib} __EOF__ $fd->close(); }, post => sub { unlink('_xyzzy.aux'); }, expected_err => '', expected_out => <<__EOF__, \@Book{ whole-collection, title = "" } __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'extract_file_1', args => '-- \'extract.file={xyzzy}\'', expected_out => '', expected_err => <<__EOF__, *** BibTool ERROR: aux file xyzzy not found. __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'extract_file_2', args => '-- \'extract.file={_xyzzy.aux}\'', prepare => sub { my $fd = new FileHandle("_xyzzy.aux",'w') || die "_xyzzy.aux: $!\n"; print $fd <<__EOF__; \\citation{whole-collection} \\bibstyle{alpha} \\bibdata{bib/xampl_s.bib} __EOF__ $fd->close(); }, post => sub { unlink('_xyzzy.aux'); }, expected_err => '', expected_out => <<__EOF__, \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX" } \@Book{ whole-collection, title = "" } __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'extract_file_3', args => '-- \'extract.file={_xyzzy.aux}\'', prepare => sub { my $fd = new FileHandle("_xyzzy.aux",'w') || die "_xyzzy.aux: $!\n"; print $fd <<__EOF__; \\citation{a} \\bibstyle{alpha} \\bibdata{_test.bib} __EOF__ $fd->close(); $fd = new FileHandle("_test.bib",'w') || die "_test.bib: $!\n"; print $fd <<__EOF__; \@string{sss="T" # t} \@string{t="ttt"#t2} \@string{t2="ttt"} \@Article{ a, author = sss, } __EOF__ $fd->close(); }, post => sub { unlink('_xyzzy.aux'); unlink('_test.aux'); }, expected_err => '', expected_out => <<__EOF__, \@STRING{t = "ttt" # t2 } \@STRING{t2 = "ttt" } \@STRING{sss = "T" # t } \@Article{ a, author = sss } __EOF__ ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/ignored_word.t0000644000175100017510000000512412646462312014666 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME ignored_word.t - Test suite for BibTool ignored.word. =head1 SYNOPSIS ignored_word.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'ignored_word_1', resource => <<__EOF__, ignored.word{BibTool} key.format=short __EOF__ bib => <<__EOF__, \@Manual{ bibtool, title = {The BibTool Manual}, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@Manual{ neugebauer:manual, title = {The BibTool Manual}, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'ignored_word_2', resource => <<__EOF__, ignored.word{BibTool} ignored.word{manual} key.format=short __EOF__ bib => <<__EOF__, \@Manual{ bibtool, title = {The BibTool Manual}, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@Manual{ neugebauer:, title = {The BibTool Manual}, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/input.t0000644000175100017510000000426112646462322013345 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME input.t - Test suite for BibTool input. =head1 SYNOPSIS input.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'input_1', args => '--input{bib/x1.bib}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => '_i_1', args => '-i bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/key_base.t0000644000175100017510000001543412646462332013775 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME key_base.t - Test suite for BibTool key.base. =head1 SYNOPSIS key_base.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; use constant BIB2 => <<__EOF__; \@Misc{ xxx, author = "A. U. Thor" } \@Misc{ xxx, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_base_digit1', resource => <<__EOF__ , key.base = digit key.format=short __EOF__ bib => BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor*1, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_base_digit2', resource => <<__EOF__ , key.base = digit key.format=short __EOF__ bib => BIB2.BIB2.BIB2.BIB2.BIB2.BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor*1, author = "A. U. Thor" } \@Misc{ thor*2, author = "A. U. Thor" } \@Misc{ thor*3, author = "A. U. Thor" } \@Misc{ thor*4, author = "A. U. Thor" } \@Misc{ thor*5, author = "A. U. Thor" } \@Misc{ thor*6, author = "A. U. Thor" } \@Misc{ thor*7, author = "A. U. Thor" } \@Misc{ thor*8, author = "A. U. Thor" } \@Misc{ thor*9, author = "A. U. Thor" } \@Misc{ thor*10, author = "A. U. Thor" } \@Misc{ thor*11, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_base_upper1', resource => <<__EOF__ , key.base = upper key.format=short __EOF__ bib => BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor*A, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_base_upper2', resource => <<__EOF__ , key.base = upper key.format=short __EOF__ bib => BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2. BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor*A, author = "A. U. Thor" } \@Misc{ thor*B, author = "A. U. Thor" } \@Misc{ thor*C, author = "A. U. Thor" } \@Misc{ thor*D, author = "A. U. Thor" } \@Misc{ thor*E, author = "A. U. Thor" } \@Misc{ thor*F, author = "A. U. Thor" } \@Misc{ thor*G, author = "A. U. Thor" } \@Misc{ thor*H, author = "A. U. Thor" } \@Misc{ thor*I, author = "A. U. Thor" } \@Misc{ thor*J, author = "A. U. Thor" } \@Misc{ thor*K, author = "A. U. Thor" } \@Misc{ thor*L, author = "A. U. Thor" } \@Misc{ thor*M, author = "A. U. Thor" } \@Misc{ thor*N, author = "A. U. Thor" } \@Misc{ thor*O, author = "A. U. Thor" } \@Misc{ thor*P, author = "A. U. Thor" } \@Misc{ thor*Q, author = "A. U. Thor" } \@Misc{ thor*R, author = "A. U. Thor" } \@Misc{ thor*S, author = "A. U. Thor" } \@Misc{ thor*T, author = "A. U. Thor" } \@Misc{ thor*U, author = "A. U. Thor" } \@Misc{ thor*V, author = "A. U. Thor" } \@Misc{ thor*W, author = "A. U. Thor" } \@Misc{ thor*X, author = "A. U. Thor" } \@Misc{ thor*Y, author = "A. U. Thor" } \@Misc{ thor*Z, author = "A. U. Thor" } \@Misc{ thor*A_, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_base_lower1', resource => <<__EOF__ , key.base = lower key.format=short __EOF__ bib => BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor*a, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_base_lower2', resource => <<__EOF__ , key.base = lower key.format=short __EOF__ bib => BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2.BIB2. BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor*a, author = "A. U. Thor" } \@Misc{ thor*b, author = "A. U. Thor" } \@Misc{ thor*c, author = "A. U. Thor" } \@Misc{ thor*d, author = "A. U. Thor" } \@Misc{ thor*e, author = "A. U. Thor" } \@Misc{ thor*f, author = "A. U. Thor" } \@Misc{ thor*g, author = "A. U. Thor" } \@Misc{ thor*h, author = "A. U. Thor" } \@Misc{ thor*i, author = "A. U. Thor" } \@Misc{ thor*j, author = "A. U. Thor" } \@Misc{ thor*k, author = "A. U. Thor" } \@Misc{ thor*l, author = "A. U. Thor" } \@Misc{ thor*m, author = "A. U. Thor" } \@Misc{ thor*n, author = "A. U. Thor" } \@Misc{ thor*o, author = "A. U. Thor" } \@Misc{ thor*p, author = "A. U. Thor" } \@Misc{ thor*q, author = "A. U. Thor" } \@Misc{ thor*r, author = "A. U. Thor" } \@Misc{ thor*s, author = "A. U. Thor" } \@Misc{ thor*t, author = "A. U. Thor" } \@Misc{ thor*u, author = "A. U. Thor" } \@Misc{ thor*v, author = "A. U. Thor" } \@Misc{ thor*w, author = "A. U. Thor" } \@Misc{ thor*x, author = "A. U. Thor" } \@Misc{ thor*y, author = "A. U. Thor" } \@Misc{ thor*z, author = "A. U. Thor" } \@Misc{ thor*a_, author = "A. U. Thor" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/key_format.t0000644000175100017510000021656712646462345014371 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME key.t - Test suite for BibTool key. =head1 SYNOPSIS key.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => '_k_1', args => '-k bib/xampl.bib', expected_out => < < '_f_short_1', args => '-f short bib/xampl.bib', expected_out => < < '_K_1', args => '-K bib/xampl.bib', expected_put => < < '_f_long_1', args => '-f long bib/xampl.bib', expected_put => < < 'f_empty_1', args => '-f empty', bib => < < < <<__EOF__; \@Unpublished{unpublished-key, author = "First A. U. Thor and Seco N. D. Author and Third A. Uthor and others", title = "This is a rather long title of an unpublished entry which exceeds one line" } \@Article{, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System} } \@BOOK{whole-collection, editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", title = "High Speed Computer and Algorithm Organization" } \@MISC{misc-minimal, key = "Missilany", note = "This is a minimal MISC entry" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_1', args => '-- key.format={short}', bib => DATA, expected_out => <<__EOF__); \@Unpublished{ thor.author.ea:this, author = "First A. U. Thor and Seco N. D. Author and Third A. Uthor and others", title = "This is a rather long title of an unpublished entry which exceeds one line" } \@Article{ aamport:gnats, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System} } \@Book{ lipcoll.lawrie.ea:high, editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", title = "High Speed Computer and Algorithm Organization" } \@Misc{ missilany, key = "Missilany", note = "This is a minimal MISC entry" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_2', args => '-- key.format={long}', bib => DATA, expected_out => <<__EOF__); \@Unpublished{ thor.fau.author.snd.ea:this, author = "First A. U. Thor and Seco N. D. Author and Third A. Uthor and others", title = "This is a rather long title of an unpublished entry which exceeds one line" } \@Article{ aamport.la:gnats, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System} } \@Book{ lipcoll.dj.lawrie.dh.ea:high, editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", title = "High Speed Computer and Algorithm Organization" } \@Misc{ missilany, key = "Missilany", note = "This is a minimal MISC entry" } __EOF__ use constant SAMPLE => <<__EOF__; \@MISC{misc, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_p1', resource => 'key.format={%p(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Thor.Meone.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_p2', resource => 'key.format={%1p(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Thor.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_p3', resource => 'key.format={%-2p(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ thor.meone.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_p4', resource => 'key.format={%+1p(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ THOR.EA, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_n1', resource => 'key.format={%n(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Thor.Meone.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_n2', resource => 'key.format={%1n(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Thor.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_n3', resource => 'key.format={%-2n(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ thor.meone.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_n4', resource => 'key.format={%+1n(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ THOR.EA, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_n5', resource => 'key.format={%.3n(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Tho.Meo.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_N1', resource => 'key.format={%N(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Thor.AU.Meone.SO.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_N2', resource => 'key.format={%1N(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Thor.AU.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_N3', resource => 'key.format={%-2N(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ thor.au.meone.so.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_N4', resource => 'key.format={%+1N(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ THOR.AU.EA, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_N5', resource => 'key.format={%.3N(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ Tho.AU.Meo.SO.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ use constant SAMPLE_NUM => <<__EOF__; \@MISC{misc, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d1', resource => 'key.format={x%d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x89, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d2', resource => 'key.format={x%1d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x9, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d3', resource => 'key.format={x%4d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x89, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d4', resource => 'key.format={x%-4d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x0089, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d5', resource => 'key.format={x%-5.2d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x00123, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d6', resource => 'key.format={x%+.3d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x0, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d7', resource => 'key.format={x%0d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_d8', resource => 'key.format={x%.3d(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ **key*, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D1', resource => 'key.format={x%D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x89, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D2', resource => 'key.format={x%1D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x89, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D3', resource => 'key.format={x%4D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x89, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D4', resource => 'key.format={x%-4D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x0089, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D5', resource => 'key.format={x%-5.2D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x00123, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D6', resource => 'key.format={x%+.3D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x0, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D7', resource => 'key.format={x%0D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ x89, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_D8', resource => 'key.format={x%.3D(pages)}', bib => SAMPLE_NUM, expected_out => <<__EOF__); \@Misc{ **key*, pages = {89--123} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_s1', resource => 'key.format={%s(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ A.-U.-Thor-and-S.-O.-Meone-and-others, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_s2', resource => 'key.format={%8s(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ A.-U.-Th, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_s3', resource => 'key.format={%-8s(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ a.-u.-th, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_s4', resource => 'key.format={%+8s(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ A.-U.-TH, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_s5', resource => 'key.format={x%0s(author)}', bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ use constant SAMPLE_TITLE => <<__EOF__; \@MISC{csim, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_T1', resource => 'key.format={%T(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ Whole, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_T2', resource => 'key.format={%2T(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ Whole-Title, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_T3', resource => 'key.format={%2.1T(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ W-T, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_T4', resource => 'key.format={%-T(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ whole, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_T5', resource => 'key.format={%+T(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ WHOLE, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_t1', resource => 'key.format={%t(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ The, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_t2', resource => 'key.format={%2t(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ The-Whole, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_t3', resource => 'key.format={%2.1t(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ T-W, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_t4', resource => 'key.format={%-t(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ the, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_t5', resource => 'key.format={%+t(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ THE, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_W1', resource => 'key.format={%W(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ Whole, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_W2', resource => 'key.format={%2W(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ WholeTitle, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_W3', resource => 'key.format={%2.1W(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ WT, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_W4', resource => 'key.format={%-W(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ whole, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_W5', resource => 'key.format={%+W(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ WHOLE, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_w1', resource => 'key.format={%w(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ The, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_w2', resource => 'key.format={%2w(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ TheWhole, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_w3', resource => 'key.format={%2.1w(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ TW, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_w4', resource => 'key.format={%-w(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ the, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_format_w5', resource => 'key.format={%+w(title)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ THE, title = "The Whole Title" } __EOF__ foreach $_ (qw/p n N/) { #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}1", resource => "key.format={x%2#$_(author)}", bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}2", resource => "key.format={x%4#$_(author)}", bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ **key*, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}3", resource => "key.format={x%-4#$_(author)}", bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}4", resource => "key.format={x%3.4#$_(author)}", bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}5", resource => "key.format={x%-3.4#$_(author)}", bib => SAMPLE, expected_out => <<__EOF__); \@Misc{ **key*, author = "A. U. Thor and S. O. Meone and others" } __EOF__ } #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_s1", resource => "key.format={x%#s(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_s2", resource => "key.format={x%13.13#s(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_s3", resource => "key.format={x%10.16#s(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_s4", resource => "key.format={x%-10.16#s(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ **key*, title = "The Whole Title" } __EOF__ foreach $_ (qw/w t/) { #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}1", resource => "key.format={x%#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}2", resource => "key.format={x%3.3#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}3", resource => "key.format={x%1.6#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}4", resource => "key.format={x%-1.6#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ **key*, title = "The Whole Title" } __EOF__ } foreach $_ (qw/W T/) { #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}1", resource => "key.format={x%#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}2", resource => "key.format={x%2.2#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}3", resource => "key.format={x%1.6#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_hash_${_}4", resource => "key.format={x%-1.6#$_(title)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ **key*, title = "The Whole Title" } __EOF__ } #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_key1", resource => "key.format={x%s(\$key)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ xcsim, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ #BUnit::run(name => "key_format_dollar_sortkey1", # resource => "key.format={x%s(\$sortkey)}", # bib => SAMPLE_TITLE, # expected_out => <<__EOF__); # #\@Misc{ xcsim, # title = "The Whole Title" #} #__EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_type1", resource => "key.format={x%s(\$type)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ xMisc, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_at_type1", resource => "key.format={x%s(\@Book)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ **key*, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_at_type2", resource => "key.format={x%s(\@Misc)}", bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ xMisc, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_at_type3", resource => 'key.format={x%s(@MISC)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ xMisc, title = "The Whole Title" } __EOF__ my ($sec,$minute,$hour,$day,$month,$year,$wday,$yday,$isdst) = localtime(time); $day = "0$day" if $day <= 9; $month++; $month = "0$month" if $month <= 9; $year += 1900; $hour = "0$hour" if $hour <= 9; $minute = "0$minute" if $minute <= 9; #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_day1", resource => 'key.format={x%s($day)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x$day, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_month1", resource => 'key.format={x%s($month)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x$month, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_year1", resource => 'key.format={x%s($year)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x$year, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_hour1", resource => 'key.format={x%s($hour)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x$hour, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_minute1", resource => 'key.format={x%s($minute)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x$minute, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_user1", resource => 'key.format={x%s($user)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x$ENV{USER}, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_dollar_hostname1", resource => 'key.format={x%s($hostname)}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ x$ENV{HOSTNAME}, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_or1", resource => 'key.format={x%#s(abc) # fallback}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ fallback, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_cond1", resource => 'key.format={(abc){then}{else}}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ else, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_cond2", resource => 'key.format={(title){then}{else}}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ then, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_cond3", resource => 'key.format={($key){then}{else}}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ then, title = "The Whole Title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => "key_format_group1", resource => 'key.format={{%N(author) # --no-author-- } {%T(title) # --no-title-- } x}', bib => SAMPLE_TITLE, expected_out => <<__EOF__); \@Misc{ --no-author--Wholex, title = "The Whole Title" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/key_make_alias.t0000644000175100017510000000664112646462356015157 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME key_make_alias.t - Test suite for BibTool key.make.alias. =head1 SYNOPSIS key_make_alias.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'key_make_alias_1', bib => <<__EOF__, \@article{xyzzy, author={A.U.Thor}, title="The Title"} __EOF__ resource => <<__EOF__, key.generation=on key.format=short key.make.alias=on __EOF__ expected_out => <<__EOF__, \@Article{ thor:title, author = {A.U.Thor}, title = "The Title" } \@ALIAS{xyzzy = thor:title } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'key_make_alias_2', bib => <<__EOF__, \@article{thor:title, author={A.U.Thor}, title="The Title"} __EOF__ resource => <<__EOF__, key.generation=on key.format=short key.make.alias=on __EOF__ expected_out => <<__EOF__, \@Article{ thor:title, author = {A.U.Thor}, title = "The Title" } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'key_make_alias_3', bib => <<__EOF__, \@article{, author={A.U.Thor}, title="The Title"} __EOF__ resource => <<__EOF__, key.generation=on key.format=short key.make.alias=on quiet=on __EOF__ expected_out => <<__EOF__, \@Article{ thor:title, author = {A.U.Thor}, title = "The Title" } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'key_make_alias_4', resource => <<__EOF__ , key.base = digit key.format=short key.make.alias=on __EOF__ bib => <<__EOF__, \@Misc{ xxx, author = "A. U. Thor" } \@Misc{ xxx, author = "A. U. Thor" } __EOF__ expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor*1, author = "A. U. Thor" } \@ALIAS{xxx = thor } \@ALIAS{xxx = thor*1 } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/key_number_separator.t0000644000175100017510000000566612646462370016443 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME key_number_separator.t - Test suite for BibTool key.number.separator. =head1 SYNOPSIS key_number_separator.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; use constant BIB2 => <<__EOF__; \@Misc{ xxx, author = "A. U. Thor" } \@Misc{ xxx, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_number_separator_digit1', resource => <<__EOF__ , key.number.separator = {--} key.base = digit key.format=short __EOF__ bib => BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor--1, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_number_separator_upper1', resource => <<__EOF__ , key.number.separator = {--} key.base = upper key.format=short __EOF__ bib => BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor--A, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'key_number_separator_lower2', resource => <<__EOF__ , key.number.separator = {--} key.base = lower key.format=short __EOF__ bib => BIB2, expected_out => <<__EOF__ ); \@Misc{ thor, author = "A. U. Thor" } \@Misc{ thor--a, author = "A. U. Thor" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/line_breaking.t0000644000175100017510000001247412646462415015007 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2015-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME line_breaking.t - Test suite for BibTool applying line breaking during printing. =head1 SYNOPSIS line_breaking.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-1', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-2', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-3', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-4', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-5', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-6', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-7', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-11', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'line_breaking-12', args => '', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/macro_file.t0000644000175100017510000000530012646462426014306 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME macro_file.t - Test suite for BibTool macro.file. =head1 SYNOPSIS macro_file.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'macro_file_1', args => '--macro.file{-} -o _null.out bib/xampl.bib', expected_out => <<__EOF__, \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } __EOF__ expected_err => <<__EOF__, *** BibTool WARNING: (line 29 in ./bib/xampl.bib): 125 non-space characters ignored. __EOF__ check => sub {unlink('_null.out'); return 0;} ); #------------------------------------------------------------------------------ BUnit::run(name => '_m_1', args => '-m - -o _null.out bib/xampl.bib', expected_out => <<__EOF__, \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } __EOF__ expected_err => <<__EOF__, *** BibTool WARNING: (line 29 in ./bib/xampl.bib): 125 non-space characters ignored. __EOF__ check => sub {unlink('_null.out'); return 0;} ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/main.t0000644000175100017510000003602112646462435013136 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME main.t - Test suite for BibTool main. =head1 SYNOPSIS main.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'main_0', args => '', expected_out => '', expected_err => ''); #------------------------------------------------------------------------------ BUnit::run(name => 'main_1', args => 'xyzzy', expected_out => '', expected_err => <<__EOF__); *** BibTool WARNING: File xyzzy not found. __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'main_2', args => 'bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => ''); #------------------------------------------------------------------------------ BUnit::run(name => 'main_3', args => 'bib/x1', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => ''); #------------------------------------------------------------------------------ BUnit::run(name => 'main_4', args => 'bib/xampl.bib', expected_out => <<__EOF__, \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } \@Article{ article-minimal, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\\mbox{G-Animal's} Journal}, year = 1986 } \@Article{ article-full, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, pages = "73+", month = jul, note = "This is a full ARTICLE entry" } \@Article{ article-crossref, crossref = {WHOLE-JOURNAL}, key = "", author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, pages = "73+", note = "This is a cross-referencing ARTICLE entry" } \@Article{ whole-journal, key = "GAJ", journal = {\\mbox{G-Animal\'s} Journal}, year = 1986, volume = 41, number = 7, month = jul, note = {The entire issue is devoted to gnats and gnus (this entry is a cross-referenced ARTICLE (journal))} } \@InBook{ inbook-minimal, author = "Donald E. Knuth", title = "Fundamental Algorithms", publisher = "Addison-Wesley", year = "{\\noopsort{1973b}}1973", chapter = "1.2" } \@InBook{ inbook-full, author = "Donald E. Knuth", title = "Fundamental Algorithms", volume = 1, series = "The Art of Computer Programming", publisher = "Addison-Wesley", address = "Reading, Massachusetts", edition = "Second", month = "10~" # jan, year = "{\\noopsort{1973b}}1973", type = "Section", chapter = "1.2", pages = "10--119", note = "This is a full INBOOK entry" } \@InBook{ inbook-crossref, crossref = "whole-set", title = "Fundamental Algorithms", volume = 1, series = "The Art of Computer Programming", edition = "Second", year = "{\\noopsort{1973b}}1973", type = "Section", chapter = "1.2", note = "This is a cross-referencing INBOOK entry" } \@Book{ book-minimal, author = "Donald E. Knuth", title = "Seminumerical Algorithms", publisher = "Addison-Wesley", year = "{\\noopsort{1973c}}1981" } \@Book{ book-full, author = "Donald E. Knuth", title = "Seminumerical Algorithms", volume = 2, series = "The Art of Computer Programming", publisher = "Addison-Wesley", address = "Reading, Massachusetts", edition = "Second", month = "10~" # jan, year = "{\\noopsort{1973c}}1981", note = "This is a full BOOK entry" } \@Book{ book-crossref, crossref = "whole-set", title = "Seminumerical Algorithms", volume = 2, series = "The Art of Computer Programming", edition = "Second", year = "{\\noopsort{1973c}}1981", note = "This is a cross-referencing BOOK entry" } \@Book{ whole-set, author = "Donald E. Knuth", publisher = "Addison-Wesley", title = "The Art of Computer Programming", series = "Four volumes", year = "{\\noopsort{1973a}}{\\switchargs{--90}{1968}}", note = "Seven volumes planned (this is a cross-referenced set of BOOKs)" } \@Booklet{ booklet-minimal, key = "Kn{\\printfirst{v}{1987}}", title = "The Programming of Computer Art" } \@Booklet{ booklet-full, author = "Jill C. Knvth", title = "The Programming of Computer Art", howpublished = "Vernier Art Center", address = "Stanford, California", month = feb, year = 1988, note = "This is a full BOOKLET entry" } \@InCollection{ incollection-minimal, author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", booktitle = "High Speed Computer and Algorithm Organization", publisher = "Academic Press", year = 1977 } \@InCollection{ incollection-full, author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", booktitle = "High Speed Computer and Algorithm Organization", number = 23, series = "Fast Computers", chapter = 3, type = "Part", pages = "179--183", publisher = "Academic Press", address = "New York", edition = "Third", month = sep, year = 1977, note = "This is a full INCOLLECTION entry" } \@InCollection{ incollection-crossref, crossref = "whole-collection", author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", pages = "179--183", note = "This is a cross-referencing INCOLLECTION entry" } \@Book{ whole-collection, editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", title = "High Speed Computer and Algorithm Organization", booktitle = "High Speed Computer and Algorithm Organization", number = 23, series = "Fast Computers", publisher = "Academic Press", address = "New York", edition = "Third", month = sep, year = 1977, note = "This is a cross-referenced BOOK (collection) entry" } \@Manual{ manual-minimal, key = "Manmaker", title = "The Definitive Computer Manual" } \@Manual{ manual-full, author = "Larry Manmaker", title = "The Definitive Computer Manual", organization = "Chips-R-Us", address = "Silicon Valley", edition = "Silver", month = apr # "-" # may, year = 1986, note = "This is a full MANUAL entry" } \@MastersThesis{ mastersthesis-minimal, author = "{\\'{E}}douard Masterly", title = "Mastering Thesis Writing", school = "Stanford University", year = 1988 } \@MastersThesis{ mastersthesis-full, author = "{\\'{E}}douard Masterly", title = "Mastering Thesis Writing", school = "Stanford University", type = "Master's project", address = "English Department", month = jun # "-" # aug, year = 1988, note = "This is a full MASTERSTHESIS entry" } \@Misc{ misc-minimal, key = "Missilany", note = "This is a minimal MISC entry" } \@Misc{ misc-full, author = "Joe-Bob Missilany", title = "Handing out random pamphlets in airports", howpublished = "Handed out at O'Hare", month = oct, year = 1984, note = "This is a full MISC entry" } \@InProceedings{ inproceedings-minimal, author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", booktitle = "Proc. Fifteenth Annual ACM" # stoc, year = 1983 } \@InProceedings{ inproceedings-full, author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", editor = "Wizard V. Oz and Mihalis Yannakakis", booktitle = "Proc. Fifteenth Annual ACM" # stoc, number = 17, series = "All ACM Conferences", pages = "133--139", month = mar, year = 1983, address = "Boston", organization = acm, publisher = "Academic Press", note = "This is a full INPROCEDINGS entry" } \@InProceedings{ inproceedings-crossref, crossref = "whole-proceedings", author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", organization = "", pages = "133--139", note = "This is a cross-referencing INPROCEEDINGS entry" } \@Proceedings{ proceedings-minimal, key = stoc-key, title = "Proc. Fifteenth Annual" # stoc, year = 1983 } \@Proceedings{ proceedings-full, editor = "Wizard V. Oz and Mihalis Yannakakis", title = "Proc. Fifteenth Annual" # stoc, number = 17, series = "All ACM Conferences", month = mar, year = 1983, address = "Boston", organization = acm, publisher = "Academic Press", note = "This is a full PROCEEDINGS entry" } \@Proceedings{ whole-proceedings, key = stoc-key, organization = acm, title = "Proc. Fifteenth Annual" # stoc, address = "Boston", year = 1983, booktitle = "Proc. Fifteenth Annual ACM" # stoc, note = "This is a cross-referenced PROCEEDINGS" } \@PhDThesis{ phdthesis-minimal, author = "F. Phidias Phony-Baloney", title = "Fighting Fire with Fire: Festooning {F}rench Phrases", school = "Fanstord University", year = 1988 } \@PhDThesis{ phdthesis-full, author = "F. Phidias Phony-Baloney", title = "Fighting Fire with Fire: Festooning {F}rench Phrases", school = "Fanstord University", type = "{PhD} Dissertation", address = "Department of French", month = jun # "-" # aug, year = 1988, note = "This is a full PHDTHESIS entry" } \@TechReport{ techreport-minimal, author = "Tom Terrific", title = "An {\$O(n \\log n / \\! \\log\\log n)\$} Sorting Algorithm", institution = "Fanstord University", year = 1988 } \@TechReport{ techreport-full, author = "Tom T{\\'{e}}rrific", title = "An {\$O(n \\log n / \\! \\log\\log n)\$} Sorting Algorithm", institution = "Fanstord University", type = "Wishful Research Result", number = "7", address = "Computer Science Department, Fanstord, California", month = oct, year = 1988, note = "This is a full TECHREPORT entry" } \@Unpublished{ unpublished-minimal, author = "Ulrich {\\"{U}}nderwood and Ned {\\~N}et and Paul {\\={P}}ot", title = "Lower Bounds for Wishful Research Results", note = "Talk at Fanstord University (this is a minimal UNPUBLISHED entry)" } \@Unpublished{ unpublished-full, author = "Ulrich {\\"{U}}nderwood and Ned {\\~N}et and Paul {\\={P}}ot", title = "Lower Bounds for Wishful Research Results", month = nov # ", " # dec, year = 1988, note = "Talk at Fanstord University (this is a full UNPUBLISHED entry)" } \@Misc{ random-note-crossref, key = {Volume-2}, note = "Volume~2 is listed under Knuth \\cite{book-full}" } __EOF__ expected_err => <<__EOF__); *** BibTool WARNING: (line 29 in ./bib/xampl.bib): 125 non-space characters ignored. __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_h_1', args => '-h', expected_out => '', expected_err => <<__EOF__ , BibTool Vers. 2.xxx (C) 1996-2xxx Gerd Neugebauer bibtool [options] [-o outfile] [[-i] infile] ... Options: -A Kind of disambiguating key strings: =0|a|A -c Include crossreferenced entries into the output (toggle) -d Check double entries (toggle) -f Key generation enabled (formated key) -F Key generation enabled with formated key -h Print this help info and exit [-i] infile Specify input file. If -i omitted it may not start with a -. If absent stdin is taken to read from. Multiple input files may be given. -k Key generation enabled. -K Key generation enabled (long key). -m macfile Dump macros to macfile. - is stdout -M macfile Dump used macros to macfile. - is stdout -o outfile Specify output file as next argument If absent stdout is taken to write to. -q Quiet mode. No warnings. -r resource Load resource file (several are possible). -R Load default resource file here. -s Sort. -S Sort reverse. -v Enable verbose mode. -V Print version and exit. -x file Extract from aux file. -X Extract regular expression. -- Evaluate one resource command . -\@ Print statistics (short). -# Print statistics. Library path: xxx Special configuration options: xxx __EOF__ fct_err => sub{local $_ = shift; s/Vers. 2.[0-9]+[-a-z]*/Vers. 2.xxx/; s/1996-2.../1996-2xxx/; s/Library path: .*/Library path: xxx/; s/Special configuration options: .*/Special configuration options: xxx/; return $_ } ); #------------------------------------------------------------------------------ BUnit::run(name => '_V_1', args => '-V', expected_out => '', expected_err => <<__EOF__ , BibTool Vers. 2.xxx (C) 1996-2xxx Gerd Neugebauer Library path: xxx Special configuration options: xxx __EOF__ fct_err => sub{local $_ = shift; s/Vers. 2.[0-9]+[-a-z]*/Vers. 2.xxx/; s/1996-2.../1996-2xxx/; s/Library path: .*/Library path: xxx/; s/Special configuration options: .*/Special configuration options: xxx/; return $_ } ); #------------------------------------------------------------------------------ BUnit::run(name => '_dash_dash_1', args => '-- xyzzy=on', expected_err => "\n*** BibTool ERROR: Resource xyzzy unknown.\n"); #------------------------------------------------------------------------------ BUnit::run(name => '_dash_dash_2', args => '--xyzzy=on', expected_err => "\n*** BibTool ERROR: Resource xyzzy unknown.\n"); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/new_field_type.t0000644000175100017510000000372612646462476015222 0ustar genegene#!/bin/perl -W # ============================================================================= # # This fiel is part of BibTool. # It is distributed under the GNU General Public License. # See the fiel COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME new_field_type.t - Test suite for BibTool new.field.type. =head1 SYNOPSIS new_field_type.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally fiels *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'new_field_type_1', args => 'bib/x1.bib', resource => <<__EOF__, new.field.type={author=rohtua} __EOF__ expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, rohtua = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/new_format_type.t0000644000175100017510000001570612646462525015423 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME new_format_type.t - Test suite for BibTool new.format.type. =head1 SYNOPSIS new_format_type.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_f1', resource => <<__EOF__ , new.format.type = {9="\%f"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ AU.SO.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_f2', resource => <<__EOF__ , new.format.type = {9="\%+f"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ AU.SO.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_f3', resource => <<__EOF__ , new.format.type = {9="\%f[:][-][;]"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ :A-U;.:S-O;.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_f4', resource => <<__EOF__ , new.format.type = {9="\%2f"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "Allan Uwe Thor and Stan Oliver Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ AlUw.StOl.ea, author = "Allan Uwe Thor and Stan Oliver Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_l1', resource => <<__EOF__ , new.format.type = {9="\%l"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U. Thor and S. O. Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ Thor.Meone.ea, author = "A. U. Thor and S. O. Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_v1', resource => <<__EOF__ , new.format.type = {9="\%v"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U. de Thor and S. O. de la Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ de.dela.ea, author = "A. U. de Thor and S. O. de la Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_v3', resource => <<__EOF__ , new.format.type = {9="\%v[:][-][;]"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U. de Thor and S. O. de la Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ :de;.:de-la;.ea, author = "A. U. de Thor and S. O. de la Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_v4', resource => <<__EOF__ , new.format.type = {9="\%1v"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U. de Thor and S. O. de la Meone and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ d.dl.ea, author = "A. U. de Thor and S. O. de la Meone and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_j1', resource => <<__EOF__ , new.format.type = {9="\%v"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U., Thor, jr. and S. O., Meone, sen. and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ jr.sen.ea, author = "A. U., Thor, jr. and S. O., Meone, sen. and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_j3', resource => <<__EOF__ , new.format.type = {9="\%v[:][-][;]"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U., Thor, jr. and S. O., Meone, sen. and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ :jr;.:sen;.ea, author = "A. U., Thor, jr. and S. O., Meone, sen. and others" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'new_format_type_j4', resource => <<__EOF__ , new.format.type = {9="\%1v"} key.format={\%.9p(author)} __EOF__ bib => <<__EOF__ , \@Misc{ x, author = "A. U., Thor, jr. and S. O., Meone, sen. and others" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ j.s.ea, author = "A. U., Thor, jr. and S. O., Meone, sen. and others" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/output_file.t0000644000175100017510000000572112646462533014553 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME main.t - Test suite for BibTool main. =head1 SYNOPSIS main.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; use constant OUT_FILE => '_output.bib'; #------------------------------------------------------------------------------ BUnit::run(name => 'output_file_0', args => "--output.file", expected_err => <<__EOF__); output.file ___________^ *** BibTool ERROR: Symbol expected. __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'output_file_1', args => "-q --output.file=".OUT_FILE." bib/x1", expected_out => '', expected_err => '', prepare => sub { unlink(OUT_FILE) if -e OUT_FILE; }, check => sub { if (-e OUT_FILE) { unlink(OUT_FILE); return 0; } print STDERR "missing ".OUT_FILE."\t"; return 1}); #------------------------------------------------------------------------------ BUnit::run(name => '_o_0', args => "-o", expected_err => <<__EOF__); *** BibTool WARNING: Missing output file name __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_o_1', args => "-q -o ".OUT_FILE." bib/x1", expected_out => '', expected_err => '', prepare => sub { unlink(OUT_FILE) if -e OUT_FILE; }, check => sub { if (-e OUT_FILE) { unlink(OUT_FILE); return 0; } print STDERR "missing ".OUT_FILE."\t"; return 1}); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/pass_comments.t0000644000175100017510000000455112646462550015066 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME pass_comments.t - Test suite for BibTool pass.comments. =head1 SYNOPSIS pass_comments.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; use constant BIB => <<__EOF__; This is a comment. \@Misc{ xxx, author = "A. U. Thor" } This is a comment. __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'pass_comments_1', resource => <<__EOF__ , pass.comments = off __EOF__ bib => BIB, expected_out => <<__EOF__ ); \@Misc{ xxx, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'pass_comments_2', resource => <<__EOF__ , pass.comments = on __EOF__ bib => BIB, expected_out => <<__EOF__ ); This is a comment. \@Misc{ xxx, author = "A. U. Thor" } This is a comment. __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print.t0000644000175100017510000000414112646462661013345 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print.t - Test suite for BibTool print. =head1 SYNOPSIS print.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_0', args => '', resource => 'print', expected_out => '', expected_err => <<__EOF__, *** BibTool ERROR: (line 2 in ./_test.rsc): Unterminated value __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_1', args => '', resource => 'print{Hello World!}', expected_out => '', expected_err => <<__EOF__, Hello World! __EOF__ ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_align_key.t0000644000175100017510000000537612646462556015405 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_align_key.t - Test suite for BibTool print.align.key. =head1 SYNOPSIS print_align_key.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_align_key_1', resource => <<__EOF__ , print.align.key = 0 __EOF__ bib => <<__EOF__ , \@Misc{ xxx, author = "A. U. Thor" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{xxx, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_align_key_2', resource => <<__EOF__ , print.align.key = 1 __EOF__ bib => <<__EOF__ , \@Misc{ xxx, author = "A. U. Thor" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{xxx, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_align_key_3', resource => <<__EOF__ , print.align.key = 24 __EOF__ bib => <<__EOF__ , \@Misc{ xxx, author = "A. U. Thor" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ xxx, author = "A. U. Thor" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_all_strings.t0000644000175100017510000000521512646462563015752 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_all_strings.t - Test suite for BibTool print.all.strings. =head1 SYNOPSIS print_all_strings.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_all_strings_1', args => '-- print.all.strings=on', bib => <<__EOF__, \@String{BT ="BibTool"} \@String{TeX ="\\TeX"} \@Manual{BibTool, title = BT, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@STRING{bt = "BibTool" } \@STRING{tex = "\\TeX" } \@Manual{ bibtool, title = bt, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_all_strings_2', args => '-- print.all.strings=off', bib => <<__EOF__, \@String{BT ="BibTool"} \@String{TeX ="\\TeX"} \@Manual{BibTool, title = BT, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@STRING{bt = "BibTool" } \@Manual{ bibtool, title = bt, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_comma_at_end.t0000644000175100017510000000444312646462567016045 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_comma_at_end.t - Test suite for BibTool print.comma.at.end. =head1 SYNOPSIS print_comma_at_end.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_comma_at_end_1', args => '-- print.comma.at.end=on bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_comma_at_end_2', args => '-- print.comma.at.end=off bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool ,title = {BibTool} ,author = {Gerd Neugebauer} ,year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_entry_types.t0000644000175100017510000001246412646462574016024 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_entry_types.t - Test suite for BibTool print.entry.types. =head1 SYNOPSIS print_entry_types.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; use constant BIB_3 =><<__EOF__; start \@article{art, author="A.U. Thor"} \@string{s ="s"} \@string{t ="t"} \@preamble{preamble} \@book{bk, author =s} \@alias{kb=bk} the comment __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_0', args => 'bib/xampl.bib', resource => <<__EOF__ , print.entry.types = {} __EOF__ expected_out => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_p1', bib => BIB_3, resource => <<__EOF__ , print.entry.types {p} __EOF__ expected_out => <<__EOF__ ); \@PREAMBLE{ preamble } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_p2', args => 'bib/xampl.bib', resource => <<__EOF__ , print.entry.types {p} __EOF__ expected_out => <<__EOF__ ); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_s1', bib => BIB_3, resource => <<__EOF__ , print.entry.types {s} __EOF__ expected_out => <<__EOF__ ); \@STRING{s = "s" } \@STRING{t = "t" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_s2', args => 'bib/xampl.bib', resource => <<__EOF__ , print.entry.types {S} __EOF__ expected_out => <<__EOF__ ); \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_S1', bib => BIB_3, resource => <<__EOF__ , print.entry.types {S} __EOF__ expected_out => <<__EOF__ ); \@STRING{s = "s" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_dollar1', bib => BIB_3, resource => <<__EOF__ , print.entry.types {\$} __EOF__ expected_out => <<__EOF__ ); \@STRING{s = "s" } \@STRING{t = "t" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_c1', ignore => 1, bib => BIB_3, resource => <<__EOF__ , print.entry.types {c} __EOF__ expected_out => <<__EOF__ ); the comment __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_a1', bib => BIB_3, resource => <<__EOF__ , print.entry.types {a} __EOF__ expected_out => <<__EOF__ ); \@ALIAS{kb = bk } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_n1', bib => BIB_3, resource => <<__EOF__ , print.entry.types {n} __EOF__ expected_out => <<__EOF__ ); \@Article{ art, author = "A.U. Thor" } \@Book{ bk, author = s } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_entry_types_1', bib => BIB_3, resource => <<__EOF__ , __EOF__ #expected_err => '', expected_out => <<__EOF__ ); \@PREAMBLE{ preamble } \@STRING{s = "s" } \@STRING{t = "t" } \@Article{ art, author = "A.U. Thor" } \@Book{ bk, author = s } \@ALIAS{kb = bk } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_equal_right.t0000644000175100017510000000444112646462602015727 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_equal_right.t - Test suite for BibTool print.equal.right. =head1 SYNOPSIS print_equal_right.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_equal_right_1', args => '-- print.equal.right=on bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_equal_right_2', args => '-- print.equal.right=off bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_indent.t0000644000175100017510000000535412646462607014715 0ustar genegene#!/usr/bin/perl -w #============================================================================== # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #============================================================================== =head1 NAME print_indent.t - Test suite for BibTool print.indent. =head1 SYNOPSIS print_indent.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_indent_1', resource => <<__EOF__ , print.indent = 0 __EOF__ bib => <<__EOF__ , \@Misc{ xxx, author = "A. U. Thor" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ xxx, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_indent_2', resource => <<__EOF__ , print.indent = 8 __EOF__ bib => <<__EOF__ , \@Misc{ xxx, author = "A. U. Thor" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ xxx, author = "A. U. Thor" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_indent_3', resource => <<__EOF__ , print.indent = 16 __EOF__ bib => <<__EOF__ , \@Misc{ xxx, author = "A. U. Thor" } __EOF__ expected_err => '', expected_out => <<__EOF__ ); \@Misc{ xxx, author="A. U. Thor" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_line_length.t0000644000175100017510000001161112646462627015717 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2015-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_line_length.t - Test suite for BibTool applying line breaking during printing. =head1 SYNOPSIS print_line_length.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-5', args => '--print.line.length=5', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{key, title={x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-10-1', args => '--print.line.length=10', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title ={x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-10-2', args => '--print.line.length=10', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title ={x aaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-10-3', args => '--print.line.length=10', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaa aaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title ={x aaaaaaaaa aaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-10-4', args => '--print.line.length=10', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaa aaaaaaaaa}, titlx = {x aaaaaaaaa aaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title ={x aaaaaaaaa aaaaaaaaa}, titlx ={x aaaaaaaaa aaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-20', args => '--print.line.length=20', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-30', args => '--print.line.length=30', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'print_line_length-30b', args => '--print.line.length=30', expected_err => '', bib => <<__EOF__, \@Article{key, title = {x aaaaaaaa} } __EOF__ expected_out => <<__EOF__); \@Article{ key, title = {x aaaaaaaa} } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_newline.t0000644000175100017510000000571712646462650015076 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_newline.t - Test suite for BibTool print.newline. =head1 SYNOPSIS print_newline.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_newline_1', args => '-- print.newline=0 bib/x1.bib bib/x1.bib', expected_out => "\n". "\@Manual{ bibtool,\n". " title = {BibTool},\n". " author = {Gerd Neugebauer},\n". " year = 2015\n". "}\n". "\@Manual{ bibtool,\n". " title = {BibTool},\n". " author = {Gerd Neugebauer},\n". " year = 2015\n". "}", expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_newline_2', args => '-- print.newline=1 bib/x1.bib bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_newline_3', args => '-- print.newline=2 bib/x1.bib bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_parentheses.t0000644000175100017510000000510312646462655015750 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_parentheses.t - Test suite for BibTool print.parentheses. =head1 SYNOPSIS print_parentheses.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_parentheses_1', args => '-- print.parentheses=on', bib => <<__EOF__, \@String{BT ="BibTool"} \@Manual{BibTool, title = BT, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@STRING(bt = "BibTool" ) \@Manual( bibtool, title = bt, author = {Gerd Neugebauer}, year = 2011 ) __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_parentheses_2', args => '-- print.parentheses=off', bib => <<__EOF__, \@String{BT ="BibTool"} \@Manual{BibTool, title = BT, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@STRING{bt = "BibTool" } \@Manual{ bibtool, title = bt, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_terminal_comma.t0000644000175100017510000000446312646462667016431 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_terminal_comma.t - Test suite for BibTool print.terminal.comma. =head1 SYNOPSIS print_terminal_comma.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_terminal_comma_1', args => '-- print.terminal.comma=on bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015, } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_terminal_comma_2', args => '-- print.terminal.comma=off bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/print_use_tab.t0000644000175100017510000000443612646462674015062 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME print_use_tab.t - Test suite for BibTool print.use.tab. =head1 SYNOPSIS print_use_tab.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'print_use_tab_1', args => '-- print.use.tab=on bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'print_use_tab_2', args => '-- print.use.tab=off bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/quiet.t0000644000175100017510000000415512646462701013340 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME quiet.t - Test suite for BibTool quiet. =head1 SYNOPSIS quiet.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'quiet_1', resource => 'quiet=on', args => 'bib/xampl.bib', expected_err => ''); #------------------------------------------------------------------------------ BUnit::run(name => '_q_1', args => '-q bib/xampl.bib', expected_err => ''); #------------------------------------------------------------------------------ BUnit::run(name => '_q_2', args => '-q xyzzy', expected_out => '', expected_err => ''); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/rename_field.t0000644000175100017510000001036012646462714014622 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2015-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME rename_field.t - Test suite for BibTool rename.field. =head1 SYNOPSIS rename_field.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'rename_field_0', args => 'bib/x1.bib', resource => 'rename.field={xyzzy = booktitle}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'rename_field_1', args => 'bib/x1.bib', resource => 'rename.field={title = booktitle}', expected_out => <<__EOF__, \@Manual{ bibtool, booktitle = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'rename_field_2', args => 'bib/x1.bib', resource => 'rename.field={Title = booktitle}', expected_out => <<__EOF__, \@Manual{ bibtool, booktitle = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'rename_field_err_1', args => 'bib/x1.bib', resource => 'rename.field={Title}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => <<__EOF__, Title _____^ *** BibTool ERROR: Symbol expected. __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'rename_field_err_2', args => 'bib/x1.bib', resource => 'rename.field={Title booktitle xxx}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => <<__EOF__, Title booktitle xxx ________________^ *** BibTool ERROR: Unexpected characters at end of string. __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'rename_field_10', args => 'bib/x1.bib', resource => 'rename.field={Title = booktitle if author "Neu"}', expected_out => <<__EOF__, \@Manual{ bibtool, booktitle = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'rename_field_11', args => 'bib/x1.bib', resource => 'rename.field={Title = booktitle if $type "Book"}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/resource.t0000644000175100017510000000514212646462721014037 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME resource.t - Test suite for BibTool resource. =head1 SYNOPSIS resource.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'resource_1', resource => <<__EOF__, resource{_rsc.rsc} __EOF__ prepare => sub { BUnit::store_file('_rsc.rsc','print{Been there}'); }, check => sub { unlink('_rsc.rsc'); return 0; }, expected_err => "Been there\n" ); #------------------------------------------------------------------------------ BUnit::run(name => '_r_1', args => "-r _rsc.rsc", prepare => sub { BUnit::store_file('_rsc.rsc','print{Been there}'); }, check => sub { unlink('_rsc.rsc'); return 0; }, expected_err => "Been there\n" ); #------------------------------------------------------------------------------ BUnit::run(name => '_r_2', args => "-r _rsc", prepare => sub { BUnit::store_file('_rsc.rsc','print{Been there}'); }, check => sub { unlink('_rsc.rsc'); return 0; }, expected_err => "Been there\n" ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/rewrite_rule.t0000644000175100017510000000573612646462725014735 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME rewrite.t - Test suite for BibTool rewrite. =head1 SYNOPSIS rewrite.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'rewrite_rule_1', args => 'bib/x1.bib', resource => 'rewrite.rule={"01"}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer} } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'rewrite_rule_2', args => 'bib/x1.bib', resource => 'rewrite.rule={"G.* N[a-z]*" # "A.U. Thor"}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {A.U. Thor}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'rewrite_rule_3', args => 'bib/x1.bib', resource => 'rewrite.rule={author title # "G.* N[a-z]*" # "A.U. Thor"}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {A.U. Thor}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'rewrite_rule_4', args => 'bib/x1.bib', resource => 'rewrite.rule={title # "G.* N[a-z]*" # "A.U. Thor"}', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/select.t0000644000175100017510000000761412646462771013502 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME select.t - Test suite for BibTool select. =head1 SYNOPSIS select.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => '_X_0', args => '-X', expected_err => <<__EOF__); *** BibTool WARNING: Missing pattern. __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_X_1', args => '-X aa', expected_err => '', bib => <<__EOF__, \@article{ aaa, author = "aa", title = "the title" } \@article{ aba, author = "bb", title = "Just another text" } __EOF__ expected_out => <<__EOF__); \@Article{ aaa, author = "aa", title = "the title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_X_2', args => '-X a+a+', expected_err => '', bib => <<__EOF__, \@article{ aaa, author = "aa", title = "the title" } \@article{ aba, author = "bb", title = "Just another text" } __EOF__ expected_out => <<__EOF__); \@Article{ aaa, author = "aa", title = "the title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_1', args => '--select\'{"aa"}\'', expected_err => '', bib => <<__EOF__, \@article{ a, author = "aa", title = "the title" } \@article{ b, author = "bb", title = "THE TITLE" } __EOF__ expected_out => <<__EOF__); \@Article{ a, author = "aa", title = "the title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_2', args => '--select\'{"title"}\'', expected_err =>'', bib => <<__EOF__, \@article{ a, author = "aa", title = "the title" } \@article{ b, author = "bb", title = "Just another text" } __EOF__ expected_out => <<__EOF__); \@Article{ a, author = "aa", title = "the title" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_3', args => '--select\'{"t.*le"}\'', expected_err =>'', bib => <<__EOF__, \@article{ a, author = "aa", title = "the title" } \@article{ b, author = "bb", title = "Just another text" } __EOF__ expected_out => <<__EOF__); \@Article{ a, author = "aa", title = "the title" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/select_by_string.t0000644000175100017510000001676612646462757015576 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME select_by_string.t - Test suite for BibTool select.by.string. =head1 SYNOPSIS select_by_string.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'select_by_string_1', args => '--select.by.string=\'{"none"}\' bib/xampl.bib', expected_out => <<__EOF__); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_by_string_2', args => '--select.by.string=\'{"anual-mi"}\' bib/xampl.bib', expected_out => <<__EOF__); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } \@Manual{ manual-minimal, key = "Manmaker", title = "The Definitive Computer Manual" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_by_string_3', args => '--select.by.string=\'{"manmaker"}\' bib/xampl.bib', expected_out => <<__EOF__); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } \@Manual{ manual-minimal, key = "Manmaker", title = "The Definitive Computer Manual" } \@Manual{ manual-full, author = "Larry Manmaker", title = "The Definitive Computer Manual", organization = "Chips-R-Us", address = "Silicon Valley", edition = "Silver", month = apr # "-" # may, year = 1986, note = "This is a full MANUAL entry" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_by_string_4', args => '--select.by.string=\'{"MISC"}\' bib/xampl.bib', expected_out => <<__EOF__); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } \@Misc{ misc-minimal, key = "Missilany", note = "This is a minimal MISC entry" } \@Misc{ misc-full, author = "Joe-Bob Missilany", title = "Handing out random pamphlets in airports", howpublished = "Handed out at O'Hare", month = oct, year = 1984, note = "This is a full MISC entry" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_by_string_10', args => '--select.by.string=\'{"MISC"}\' bib/xampl.bib', expected_out => <<__EOF__); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } \@Misc{ misc-minimal, key = "Missilany", note = "This is a minimal MISC entry" } \@Misc{ misc-full, author = "Joe-Bob Missilany", title = "Handing out random pamphlets in airports", howpublished = "Handed out at O'Hare", month = oct, year = 1984, note = "This is a full MISC entry" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_by_string_11', args => '--select.by.string=\'{note "Kn"}\' bib/xampl.bib', expected_out => <<__EOF__); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } \@Misc{ random-note-crossref, key = {Volume-2}, note = "Volume~2 is listed under Knuth \\cite{book-full}" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_by_string_12', args => '--select.by.string=\'{$type "misc"}\' bib/xampl.bib', expected_out => <<__EOF__); \@PREAMBLE{ "\\newcommand{\\noopsort}[1]{} " # "\\newcommand{\\printfirst}[2]{#1} " # "\\newcommand{\\singleletter}[1]{#1} " # "\\newcommand{\\switchargs}[2]{#2#1} " } \@STRING{acm = "The OX Association for Computing Machinery" } \@STRING{stoc = " Symposium on the Theory of Computing" } \@STRING{stoc-key= "OX{\\singleletter{stoc}}" } \@Misc{ misc-minimal, key = "Missilany", note = "This is a minimal MISC entry" } \@Misc{ misc-full, author = "Joe-Bob Missilany", title = "Handing out random pamphlets in airports", howpublished = "Handed out at O'Hare", month = oct, year = 1984, note = "This is a full MISC entry" } \@Misc{ random-note-crossref, key = {Volume-2}, note = "Volume~2 is listed under Knuth \\cite{book-full}" } __EOF__ #------------------------------------------------------------------------------ #BUnit::run(name => 'select_by_non_string_1', # args => '--select.by.non.string=\'{"aa"}\'', #expected_err=>'', # bib => <<__EOF__, #\@article{ a, # author = "aa", # title = "the title" #} #\@article{ b, # author = "ab", # title = "the title" #} #__EOF__ # expected_out => <<__EOF__); #__EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/select_crossrefs.t0000644000175100017510000001074712646462764015576 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME select_crossrefs.t - Test suite for BibTool select.crossrefs. =head1 SYNOPSIS select_crossrefs.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'select_crossrefs_0', args => '--select\'{"aa"}\' -- select.crossrefs=off', expected_err =>'', bib => <<__EOF__, \@article{ a, author = "aa", title = "the title", crossref= "b" } \@article{ b, author = "bb", title = "THE TITLE" } __EOF__ expected_out => <<__EOF__); \@Article{ a, author = "aa", title = "the title", crossref = "b" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_crossrefs_1', args => '--select\'{"aa"}\' -- select.crossrefs=on', expected_err => '', bib => <<__EOF__, \@article{ a, author = "aa", title = "the title", crossref= "b" } \@article{ b, author = "bb", title = "THE TITLE" } __EOF__ expected_out => <<__EOF__); \@Article{ a, author = "aa", title = "the title", crossref = "b" } \@Article{ b, author = "bb", title = "THE TITLE" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'select_crossrefs_2', args => '--select\'{"aa"}\' -- select.crossrefs=on', expected_err => '', bib => <<__EOF__, \@article{ a, author = "aa", title = "the title", crossref= "b" } \@article{ b, author = "bb", title = "THE title", crossref= "c" } \@article{ c, author = "cc", title = "THE TITLE" } __EOF__ expected_out => <<__EOF__); \@Article{ a, author = "aa", title = "the title", crossref = "b" } \@Article{ b, author = "bb", title = "THE title", crossref = "c" } \@Article{ c, author = "cc", title = "THE TITLE" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_X_c_1', args => '-X aa -c', expected_err => '', bib => <<__EOF__, \@article{ aa, author = "aa", title = "the title", crossref= "b" } \@article{ b, author = "bb", title = "THE TITLE" } __EOF__ expected_out => <<__EOF__); \@Article{ aa, author = "aa", title = "the title", crossref = "b" } \@Article{ b, author = "bb", title = "THE TITLE" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => '_X_c_2', args => '-X aa -c', expected_err => '', bib => <<__EOF__, \@article{ aa, author = "aa", title = "the title", crossref= "b" } \@article{ b, author = "bb", title = "THE title", crossref= "c" } \@article{ c, author = "cc", title = "THE TITLE" } __EOF__ expected_out => <<__EOF__); \@Article{ aa, author = "aa", title = "the title", crossref = "b" } \@Article{ b, author = "bb", title = "THE title", crossref = "c" } \@Article{ c, author = "cc", title = "THE TITLE" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/sort.t0000644000175100017510000003001212646463000013160 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME sort.t - Test suite for BibTool sort. =head1 SYNOPSIS sort.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => '_s_1', args => '-s bib/xampl_s.bib', expected_out => < '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'sort_1', args => '--sort=on bib/xampl_s.bib', expected_out => < '' ); #------------------------------------------------------------------------------ BUnit::run(name => '_S_1', args => '-S bib/xampl_s.bib', expected_out => < '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'sort_reverse_1', args => '--sort=on --sort.reverse=on bib/xampl_s.bib', expected_out => < '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'sort_reverse_2', args => '--sort=on --sort.reverse=off bib/xampl_s.bib', expected_out => < '' ); 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/suppress_initial_newline.t0000644000175100017510000000374112646463006017326 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME suppress_initial_newline.t - Test suite for BibTool suppress.initial.newline. =head1 SYNOPSIS suppress_initial_newline.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'suppress_initial_newline_1', args => '-- suppress.initial.newline=on bib/x1.bib', expected_out => <<__EOF__, \@Manual{ bibtool, title = {BibTool}, author = {Gerd Neugebauer}, year = 2015 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/symbol_type.t0000644000175100017510000000715712646463012014560 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME symbol_type.t - Test suite for BibTool symbol.type. =head1 SYNOPSIS symbol_type.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'symbol_type_0', args => '-- symbol.type=123', bib => '', expected_out => <<__EOF__, __EOF__ expected_err => <<__EOF__ *** BibTool: Unknown symbol type ignored. __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'symbol_type_1', args => '-- symbol.type=xyz', bib => '', expected_out => <<__EOF__, __EOF__ expected_err => <<__EOF__ *** BibTool: Unknown symbol type ignored. __EOF__ ); #------------------------------------------------------------------------------ BUnit::run(name => 'symbol_type_2', args => '-- symbol.type=upper', bib => <<__EOF__, \@String{BT ="BibTool"} \@Manual{BibTool, title = BT, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@STRING{BT = "BibTool" } \@Manual{ bibtool, TITLE = BT, AUTHOR = {Gerd Neugebauer}, YEAR = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'symbol_type_3', args => '-- symbol.type=lower', bib => <<__EOF__, \@String{BT ="BibTool"} \@Manual{BibTool, Title = BT, Author = {Gerd Neugebauer}, Year = 2011 } __EOF__ expected_out => <<__EOF__, \@STRING{bt = "BibTool" } \@Manual{ bibtool, title = bt, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ BUnit::run(name => 'symbol_type_4', args => '-- symbol.type=cased', bib => <<__EOF__, \@String{BT ="BibTool"} \@Manual{BibTool, title = BT, author = {Gerd Neugebauer}, year = 2011 } __EOF__ expected_out => <<__EOF__, \@STRING{Bt = "BibTool" } \@Manual{ bibtool, Title = Bt, Author = {Gerd Neugebauer}, Year = 2011 } __EOF__ expected_err => '' ); #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/tex_define.t0000644000175100017510000001023412646463017014317 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME tex_define.t - Test suite for BibTool tex.define. =head1 SYNOPSIS tex_define.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =head1 BUGS =over 4 =item * ... =back =cut use strict; use BUnit; #------------------------------------------------------------------------------ BUnit::run(name => 'tex_define_0', resource => <<__EOF__ , key.format=short __EOF__ bib => <<__EOF__, \@Misc{ thor, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ expected_out => <<__EOF__ ); \@Misc{ thor:x, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'tex_define_1', resource => <<__EOF__ , tex.define = {\\TeX=TeX} key.format=short __EOF__ bib => <<__EOF__, \@Misc{ thor, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ expected_out => <<__EOF__ ); \@Misc{ thor:xtex, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'tex_define_2', resource => <<__EOF__ , tex.define = {\\TeX =TeX} key.format=short __EOF__ bib => <<__EOF__, \@Misc{ thor, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ expected_out => <<__EOF__ ); \@Misc{ thor:xtex, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'tex_define_3', resource => <<__EOF__ , tex.define = {\\TeX = TeX} key.format=short __EOF__ bib => <<__EOF__, \@Misc{ thor, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ expected_out => <<__EOF__ ); \@Misc{ thor:xtex, author = "A. U. Thor", title = "X\\TeX{} rulez" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'tex_define_4', resource => <<__EOF__ , tex.define = {ü = ue} key.format=short __EOF__ bib => <<__EOF__, \@Misc{ thor, author = "A. U. Thor", title = "München" } __EOF__ expected_out => <<__EOF__ ); \@Misc{ thor:muenchen, author = "A. U. Thor", title = "München" } __EOF__ #------------------------------------------------------------------------------ BUnit::run(name => 'tex_define_5', resource => <<__EOF__ , tex.define = {\\TeX = TeX} tex.define = {\\protect[1]=#1} key.format=short __EOF__ bib => <<__EOF__, \@Misc{ thor, author = "A. U. Thor", title = "x\\protect{\\TeX}" } __EOF__ expected_out => <<__EOF__ ); \@Misc{ thor:xtex, author = "A. U. Thor", title = "x\\protect{\\TeX}" } __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: BibTool/test/verbose.t0000644000175100017510000000577112646463025013663 0ustar genegene#!/bin/perl -W # ============================================================================= # # This file is part of BibTool. # It is distributed under the GNU General Public License. # See the file COPYING for details. # # (c) 2011-2016 Gerd Neugebauer # # Net: gene@gerd-neugebauer.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #*============================================================================= =head1 NAME verbose.t - Test suite for BibTool verbose. =head1 SYNOPSIS verbose.t =head1 DESCRIPTION This module contains some test cases. Running this module as program will run all test cases and print a summary for each. Optionally files *.out and *.err are left if the expected result does not match the actual result. =head1 OPTIONS none =head1 AUTHOR Gerd Neugebauer =cut use strict; use BUnit; my @library_path; my $fs; { local $_ = BUnit::get_library_path(); $_ = '.' if $_ eq 'none'; if (m/;/) { @library_path = split /;/; } else { @library_path = split /:/; } if (m/\\/) { $fs = '\\'; } else { $fs = '/'; } } my $options = BUnit::get_configuration_options(); my $xampl = "--- BibTool: Trying .${fs}bib/xampl.bib\n"; $xampl = '' if $options =~ m/kpathsea/; #------------------------------------------------------------------------------ BUnit::run(name => 'verbose_1', resource => <<__EOF__, verbose =on __EOF__ args => 'bib/xampl.bib', expected_err => <<__EOF__); $xampl--- BibTool: Reading bib/xampl.bib ++ *** BibTool WARNING: (line 29 in .${fs}bib/xampl.bib): 125 non-space characters ignored. ++++++++++++++++++++++++++++++++++--- BibTool: Done with bib/xampl.bib __EOF__ my $t = ''; foreach $_ (@library_path) { $t .= "--- BibTool: Trying $_$fs.bibtoolrsc\n--- BibTool: Trying $_$fs.bibtoolrsc.rsc\n"; } #------------------------------------------------------------------------------ BUnit::run(name => '_v_1', args => '-v bib/xampl.bib', expected_err => <<__EOF__); --- BibTool: Trying $ENV{HOME}$fs.bibtoolrsc --- BibTool: Trying $ENV{HOME}$fs.bibtoolrsc.rsc $t$xampl--- BibTool: Reading bib/xampl.bib ++ *** BibTool WARNING: (line 29 in .${fs}bib/xampl.bib): 125 non-space characters ignored. ++++++++++++++++++++++++++++++++++--- BibTool: Done with bib/xampl.bib __EOF__ 1; #------------------------------------------------------------------------------ # Local Variables: # mode: perl # End: