%%%%%%%%%%%%%%% DATABASE STYLE %%%%%%%%%%%%%%%%%% % % db.sty -- version 2.3 % % Style to generate listings, to send out letters, etc. using % a database. % % Version 2.2 (11/22/91) % % Written by George Panagopoulos (georgios@umiacs.umd.edu) % % Version 2.3 (01/16/93) % % Modified by Jose Alberto Fernandez (alberto@cs.umd.edu) % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % If you have never use db.sty you should look first at the simple % examples presented in the NEXT section, before trying to understand % the new features. % % CHANGES from version 2.2 % % In version 2.3 there are two new features, a new macro to do % conditional expansion based on the values of fields in the entry, % and an extended syntax for the conditions that allow conjunctive as % well as disjunctive selction operators. % % 1) There is a new macro \dbif[]{then-text}{else-text} that % can be used to do conditional insertion of text in the generated % letter. Ex: % % Assume that your database uses a field \position that is set to % 'academic' or 'industry' depending in the kind of place you are % sending your application letter. You can add conditional sentences % in your letter as follows: % % ``. . . I have \dbif[position=academic]{5 year of experience in % teaching undergraduate courses . . . .}{work in the development of % large scale applications in the area of . . .}. . .'' % % 2) In the previous version of db.sty one could only check if a % particular field was defined or not. Now it is possible to select % depending on more complicated queries. The general syntax of the % selector is as follows: % % := [;. . .;] % % := ,. . ., % % := = % := % % The ``;'' operator represents OR; the ``,'' operator represents AND; % an expresion using ``='' indicates that the field named must have % that particular value for the selection to apply; and a field name % with no ``='' means that the field must be have some value % assigned on this case. (A value different than empty). Ex: % % \dbif[a,b=17;b=27]{text1}{text2}: It will write ``text1'' if the % field ``a'' is defined AND the field ``b'' expands to the text % ``17'' OR if ``b'' expand to ``27'' no matter what is the value of % ``a''. % % \db{file1}[letter={to be sent}]: It will only consider those % tuples from the database file ``file1.tdb'' that define the field % ``letter'' to expend to the text ``to be sent''. % % %%%%%%%%%%%% SAMPLE DATABASE FILE mydb.tdb: % % % Schema definition % % \fields{FName, LName, % Email, Addr, % local} % % % Database % % \tuple{FName= George, % LName= Panagopoulos, % Addr= {CS Dept., U of MD, College Park 20742}, % Email= {\tt georgios@umiacs.umd.edu}, % local= 1} % % \tuple{FName= Somebody, % LName= Else, % Email= {\tt sb@elsewhere}} % all other fields empty % % \tuple{FName= Ten, % LName= \FirstName} % %%%%%%%%%%%%%% SAMPLE USE FILE mydb.tex: % % \documentstyle[db]{article} % % \begin{document} % % % List 1 % % \newcommand{\tupletext}{\thetuplectr & \FName\ \LName & \Email \\} % \begin{tabular}{rll} % \db{mydb} % Lists all % \end{tabular} % === % \thetuplectr\ person(s) listed % % % List 2 % % \renewcommand{\tupletext}{\FName\ (\Email)} % \ref{num:tuples} local person(s): % % \begin{enumerate} % \db{mydb}[local] % lists all that have nonempty \local % \label{num:tuples} % \end{enumerate} % % \end{document} % %%%%%%%%%%%%%% OUTPUT of mydb.tex: % % 1 George Panagopoulos georgios@umiacs.umd.edu % 2 Somebody Else sb@elsewhere % 3 Ten Ten % === % 3 person(s) listed % % 1 person(s) below: % % 1. George (georgios@umiacs.umd.edu) % %%%%%%%%%%%%%%% NOTES (refer to example above) % % Database files have the extension ".tdb". % % Field order is irrelevant. % % A subset of the fields may be given as argument in the \tuple command. % The rest become empty. % % TeX/LaTeX commands are valid inside field values. % % Other fields are valid inside field values. % % A field value must not contain a comma, unless the comma is enclosed % in braces. % % White space is insignificant outside \fields and \tuple commands in % the database file. % % White space is insignificant inside a \fields or a \tuple command, % except between the first letter of a field name and the following % equal sign, and between the first letter of a field value and the % following comma or closing brace. % Therefore: % In a \fields command, *there must be no space between the field name % and the following comma or closing brace*: % \fields{ Name, Addr} % is valid, but % \fields{Name ,Addr} % is invalid, and so is % \fields{Name,Addr } % In a \tuple command, *there must be no space between the field name % and the equal sign, and no unwanted spaces between the field value % and the following comma or closing brace*: % \tuple{ Name= x xx , Addr= yy y } % is equivalent to % \tuple{Name={x xx },Addr={yy y }}, % but % \tuple{Name =xxx,Addr=yyy} % is invalid. % % Beware of conflicts between field names and other TeX macros. The % \fields command issues a warning if your field name conflicts with an % already defined macro, but goes on to redefine it anyway. % % The field macros become undefined after the execution of the the \db % command. The old values (if applicable) are NOT restored. % % The same database and more than one databases may be included in the % same document. % % The counter {tuplectr} is used to count tuples. The macro \thetuplectr % may be used and/or modified at wish. The value of the counter is saved % in the \ref variable in the end of the \db command. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% MODIFIED \@for LOOP CONSTRUCT % LaTeX's @for expands the list (with \edef\@fortmp{...}), which is % undesirable, since it tries to expand the field value, which may not % make sense until inside the environment that encloses \db. % Therefore \@foreach is used instead during tuple parsing. % \@foreach does not work for empty lists. \def\@foreach#1:=#2\do#3{\expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcounter{tuplectr} %%%%%%%%%%%% USEFUL MACROS \def\ignorewhitespace{\catcode`\ =9\catcode`\^^M=9} \def\noignorewhitespace{\catcode`\ =10\catcode`\^^M=5} \ignorewhitespace \long\def\db@ifb#1{ % trim one space from #1, if needed \ifx \space #1 \else #1 \fi} %%%%%%%%%%%% SCHEMA READING \def\chk@fld@name#1{ % check fldname #1 for conflict with other macros \expandafter\ifx \expandafter \relax \csname#1\endcsname % if undefined \else \expandafter\let\csname#1\endcsname\relax % undefine macro \typeout{Warning: \space field \space name \space \expandafter\string\csname#1\endcsname \space redefines \space a \space TeX \space macro} \fi} \def\@field#1{ % expand \init@fields with: \def\#1{} (#1=fldname) % and \undef@fields with: \let\#1\relax \chk@fld@name{#1} \edef\init@fields{ \init@fields \expandafter\def\csname#1\endcsname{}} \edef\undef@fields{ \undef@fields \expandafter\let\csname#1\endcsname\relax}} \def\parse@fld@names#1{ % set \init@fields to clear all fields % and \undef@fields to undef all field macros \@for\fld@name:=#1 \do {\@field{\fld@name}}} \def\fields#1{ % read field names (keeps ignoring whitespace) \edef\init@fields{} \edef\undef@fields{} \parse@fld@names{#1}} %%%%%%%%%%%% TUPLE PARSING \long\def\@setfield#1=#2,{ \expandafter\def\csname\db@ifb#1\endcsname{#2}} \long\def\parse@fields#1{ \@foreach\@args:=#1 \do {\expandafter\@setfield\@args,}} %%%%%%%%%%%% TUPLE SELECTION \newif \ifdb@test \def\makedb@test#1=#2=#3,{ % test if condition satisfied % #1: Field, #2: Selection value, #3: nouse \bgroup% Only macros defined here can be global \let\\=\relax% Hack for multiline fields \@ifundefined{#1}{\gdef\db@testval{}% }{% \xdef\db@testval{\csname#1\endcsname}}% eval field \xdef\db@select{#2}% get selection value \egroup% % \typeout{\db@testval = \db@select}% \ifx \empty \db@select % ignore tuple if \db@testval=\empty \ifx \db@testval \empty% \db@testfalse% \fi% \else% ignore tuple if \db@testval=/=\db@select \ifx \db@testval \db@select% \else \db@testfalse% \fi% \fi} \long\def\db@and#1#2#3{% If #1 is satisfied then #2 else #3 % \typeout{[#1]}% \db@testtrue% \@foreach\db@test:=#1% \do{\expandafter\makedb@test\db@test==,}% \ifdb@test #2\else #3\fi% } \long\def\db@or[#1;#2]#3{% #1 OR #2 then #3 else #4 \ifx #1\empty% \else% \db@and{#1}{#3}{% \expandafter\db@or\expandafter[#2]{#3}}% \fi } \long\def\dbif[#1]#2#3{% #1 disjunction separated by commas \begingroup% \def\db@else{#3} \db@or[#1;;]{#2\let\db@else\relax}% Add ;; to mark end-of-list \db@else \endgroup% } \let\dbexpr\dbif % Old syntax for conditionals. %%%%%%%%%%% TUPLE WRITING \def\print@tuple{ % print tuple value as requested \ifx \empty \db@expr % always print \refstepcounter{tuplectr} \tupletext \else % evaluate expr fileds \expandafter\dbif\expandafter[\db@expr]{ \refstepcounter{tuplectr} \tupletext }{} \fi} %%%%%%%%%%%% TUPLE READING \long\def\@tuple#1{ % parse tuple and call \print@tuple \init@fields % empty field values \parse@fields{#1} \print@tuple \ignorewhitespace} \def\tuple{ % read tuple, print \tupletext if \db@flag not empty \noignorewhitespace % will be restored by \@tuple \@tuple} \long\def\notuple#1{} % ignore entry %%%%%%%%%%%% DB READING \def\@db#1[#2]{ % #1=file, #2=fields to be tested \def\db@expr{#2} \setcounter{tuplectr}{0} \ignorewhitespace \@input{#1.tdb} \undef@fields \noignorewhitespace} \def\db#1{ % read database, print \tupletext for each included tuple \@ifnextchar [ {\@db#1} {\@db#1[]}} \noignorewhitespace -- : Jose Alberto Fernandez R \ | / INTERNET: alberto@cs.umd.edu : : Dept. of Computer Sc. \ | / BITNET: alberto@cs.umd.edu : : University of Maryland \ | / PHONE: (301) 405-2716 : : College Park, MD 20742 \ | / FAX/HOME: (202) 265-5784 :