%\iffalse % % file: mkaddr.dtx % % This file is distributed as-is, with no warranty whatsoever. % Out of courtesy to others, please do not distribute the % files contained in this file separately, but always % together with this file and the documentation it contains. % %\fi % % \def\fileversion{3.1.1.1} % \def\filedate{1998/01/17 18:15:06} % % \iffalse % %<*driver> \documentclass{ltxdoc} %\CodelineIndex %\EnableCrossrefs \begin{document} \OnlyDescription % Comment out for implementation details \DocInput{mkaddr.dtx} \end{document} % %\fi % %\iffalse % Source tree moved under RCS % --------------------------- % mkaddr.dtx,v % Revision 3.1.1.1 1998/01/17 18:15:06 root % Release code, checksum verified % % Revision 3.1 1998/01/17 17:13:48 root % Release code % % Revision 2.3 1997/12/06 21:15:31 root % *** empty log message *** % % Revision 2.2 1997/11/07 10:44:05 root % Release code. % % Revision 2.1.1.1 1997/11/04 05:06:07 root % Development branch % % Revision 2.1 1997/11/01 14:58:44 bennett % Release code. % % Revision 1.1 1997/10/29 08:17:52 root % Initial revision % %\fi % % % \title{The \texttt{mkaddr} Tcl script\thanks{This file is version number % \fileversion{}. It was last revised on % \filedate{}.}} % % \author{Frank G. Bennett, Jr.} % % \maketitle % % \setcounter{StandardModuleDepth}{1} % \DeleteShortVerb{\|} % \MakeShortVerb{\"} % % \begin{abstract} % \noindent The utilities in this bundle % can be used together to generate address lists from % a database in the format used by the marvellous BBDB database % for Emacs. % \end{abstract} % % \CheckSum{392} % % \section{Installation and Use} % % The script is designed for use on a Unix system (if % you haven't already moved to Linux, you might consider % joining the gathering). You will need to have Emacs installed % on your system. You will also need the BBDB extensions, % which produce and maintain a database file, ".bbdb", % in your home directory. You should also have the % AUC\TeX{} extensions to Emacs installed, for editing, compiling, % previewing and printing \LaTeX{} documents. You will % also need "dvips" and, if (like me) you don't have % access to a PostScript printer, "ghostscript" --- or % some other combination of printing gear for which % page rotation is supported in the "graphics" bundle. Your % \TeX{} system will need the files in the "graphics" % bundle, and the "autofilo" package from the "calendar" % bundle for making filofax page frames. % % In your \texttt{/etc} directory, % you will need a format file or files. Each should % have the name "addresses", followed by an extension. % The extension(s) will be used by the first mandatory % option to the script. On my system, I have two % format files, "mkaddr.Frank" and "mkaddr.Mieko", % which produce pages suitable for my own and my wife's % diary, respectively. Each file is simply a \LaTeX{} % document, with "%%BODY%%" where the list of addresses % should be inserted. An example is given below. Note % that you will need to edit the script to reflect the % names of your format files. % % The ".bbdb" database is designed for use with email % systems, adding entries for your correspondents on % the fly as mail is received. To make it easier to add entries for % people with whom you have not corresponded by email, you % may want to add a suitable chunk of elisp to your % ".emacs" file. A chunk of such code is given below. % It sets your "f12" key to add a new entry, prompting % for details. Edit to taste (especially note the % "[M]" and "[F]"; you will want to change these. % % Flags for extracting data from the list should be % put into the "Notes:" field, in square braces. % % Extract everything, edit and install the script, % install the style, % and install one or more format files. % Run the script and read the instructions. On my system, % the command "mkaddr Frank [AaBb] [F]" will make a % file "mkaddr.tex" in the current directory, formatted % as specified in the format file "\etc\mkaddr.Frank", % containing all entries beginning with "A" or "a", % or "B" or "b", and flagged with "[F]". Run the % file through \LaTeX{} and "dvips", and you have an address list. % % % \StopEventually{\PrintIndex} % % \section{Sample Format File} % \begin{macrocode} %<*format> \documentclass{filoaddr} \begin{document} \begin{addresses}{% topmargin=2cm, rightmargin=3cm, pageheight=172mm, pagewidth=95mm, columnsep=14pt, punchcluster=3, punchgroups=2, interspace=51.25mm, intraspace=19.25mm, grip=5mm, punchmargin=2mm, punchpoints=15, topspace=2pt, bottomspace=1.5cm} %%BODY%% \end{addresses} \end{document} % % \end{macrocode} % % \section{Elisp for \texttt{.emacs}} % % \begin{macrocode} %<*elisp> ;; Essential add-on for BBDB (defun bbdb-create-external () "Prompt for and create a record. Hacked from bbdb-read-new-record." (interactive) (let ((name (bbdb-read-string "Name: ")) (company (bbdb-read-string "Company: ")) (net (bbdb-split (bbdb-read-string "Network Address: ") ",")) (addrs (let (L L-tail str addr) (while (not (string= "" (setq str (bbdb-read-string "Address Description [RET when no more addrs]: ")))) (setq addr (make-vector bbdb-address-length nil)) (bbdb-record-edit-address addr str) (if L (progn (setcdr L-tail (cons addr nil)) (setq L-tail (cdr L-tail))) (setq L (cons addr nil) L-tail L))) L)) (phones (let (L L-tail str) (while (not (string= "" (setq str (bbdb-read-string "Phone Location [RET when no more phones]: ")))) (let* ((phonelist (bbdb-error-retry (bbdb-parse-phone-number (read-string "Phone: " (and bbdb-default-area-code (format "(%03d) " bbdb-default-area-code)))))) (phone (apply 'vector str (if (= 3 (length phonelist)) (nconc phonelist '(0)) phonelist)))) (if L (progn (setcdr L-tail (cons phone nil)) (setq L-tail (cdr L-tail))) (setq L (cons phone nil) L-tail L)))) L)) (notes (bbdb-read-string "Additional Comments: " "[M][F]"))) (if (string= company "") (setq company nil)) (if (string= name "") (setq name nil)) (if (string= notes "") (setq notes nil)) (bbdb-display-records (list (bbdb-create-internal name company net addrs phones notes))))) (global-set-key [f12] 'bbdb-create-external) % % \end{macrocode} % % \section{The Script} % % You must edit this file for your system. Search % especially for instances of "Frank" and "Mieko". % % \begin{macrocode} %<*script> #!/usr/local/bin/tclsh if {[catch "kanji defaultInputCode EUC" errormsg]}\ {puts "Running $argv0 without Japanese support." puts "For Japanese support, you need to use a Japanized" puts "Tcl interpreter.\n"}\ {} # This script parses a database in the format used by # the Insidious Big Brother Database for Emacs. It can # be adapted to output LaTeX lists of contents and so forth. set format [lindex $argv 0] set range [lindex $argv 1] set condition [lindex $argv 2] set usage "Usage is: $argv0 \ \[\] \[\]\ \n(Square braces are literal)\ \n(\ is one of \"Mieko\" or \"Frank\")" if {[string match $format "Mieko"]+\ [string match $format "Frank"]==0}\ {puts "$usage"; exit}\ {} if {[regexp {\[.*\]} $condition ignore]==0}\ {puts "$usage"; exit}\ {} if {[regexp {\[.*\]} $range ignore]==0}\ {puts "$usage"; exit}\ {} puts "Creating LaTeX2e file mkaddr.tex ..." regexp {\[(.*)\]} $condition ignore condition set condition "\\\[$condition\\\]" set ifh [open "/home/bennett/.bbdb"] set ofh [open "./mkaddr.tex" w+] set counter 0 set temp "" # Let's grab the content of a header file set header [open "/etc/mkaddr.$format" r] while 1 { if {[gets $header line] == -1} break if {[string match $line "%%BODY%%"]} break puts $ofh $line } while 1 { if {[gets $ifh line] == -1} break regsub -all {([ "])\\"} $line {\1``} line regsub -all {\\"([^A-Za-z])} $line {''\1} line regsub -all {\\n} $line { } line regsub -all {([^\])%} $line {\1\\%} line regsub -all {([^\])&} $line {\1\\\&} line set fn nil set ln nil set aka nil set co nil set ph nil set ad nil set net nil set op nil regexp { *(nil|\"[^"]*\")\ +(nil|\"[^"]*\")\ +(nil|\(\".*\"\))\ +(nil|\"[^"]*\")\ +(nil|\(\[.*\]\))\ +(nil|\(\[.*\]\))\ +(nil|\(\".*\"\))\ +(nil|\(\(.*\)\)|\"[^"]*\")\ +nil} $line ignore fn ln aka co ph ad net op # # Make lone first names into lone last names if {[string match $ln "nil"]}\ {set ln $fn set fn nil}\ {} # Check that we're in the range specified if {[regexp "\"$range" $ln ignore]}\ {}\ {if {[string match $ln nil]}\ {if {[regexp "\"$range" $co ignore]}\ {}\ {continue}}\ {continue}} # # Fish out the notes field so we can check whether this # record matches the specified conditions set tempone "" set temptwo "" regexp {\(notes \. \"([^"]*)\"|\"([^"]*)\"$} $op \ ignore tempone temptwo if {[string match $temptwo ""]} \ {set notes $tempone} \ {set notes $temptwo} if {[string match "*$condition*" $notes]} {} {continue} # # Are all three names missing? If so, skip it. if { [expr 3 == \ [string match $fn "nil"]+\ [string match $ln "nil"]+\ [string match $co "nil"]] }\ {}\ { # Each entry is put in a parbox to keep it on one page. # The parbox opens with a vskip to make a little room # at the top of the page and between entries. puts $ofh "\\entry\{%" # Are both the first and last name missing? If so, # we skip that line. set counter [expr $counter + 1] if { [expr 2 == \ [string match $fn "nil"]+\ [string match $ln "nil"]] }\ {}\ {regexp {\"(.*)\"} $fn ignore fn regexp {\"(.*)\"} $ln ignore ln puts -nonewline "$fn $ln" set ln " \\textbf\{$ln\}" puts $ofh "$fn$ln\\\\"} # Is the company name missing? If so, we'll # skip that line. if { [string match $co "nil"] }\ {}\ {regexp {\"(.*)\"} $co ignore co puts $ofh "\\textbf\{$co\}\\\\" puts -nonewline $co} puts "" # Spit out any telephone numbers for this entry. if {[string match $ph nil]} {set ph ""} {} regexp {\((\[.*\])\)} $ph ignore ph while {[string match $ph ""] == 0} { set temp "" regexp {\[([^]]*)\](.*)} $ph ignore temp ph regexp {\"([^"]*)\" *\"([^"]*)\"} $temp ignore temp number puts -nonewline $ofh " \{\\small $number ($temp)\}" if {[string match $ph ""] == 0}\ {puts $ofh "\\\\"}\ {if {[string match $ad nil]+[string match $net nil]==2}\ {puts $ofh ""}\ {puts $ofh "\\\\"}} } # Spit out any addresses for this entry. if {[string match $ad nil]} {set ad ""} {} while {[string match $ad ""] == 0} { set temp "" set lineone "" set linetwo "" set linethree "" set city "" set state "" set zip "" set bridge "" regexp {\(\[([^]]*)\](.*)\)} $ad ignore ad temp regexp {\"([^"]*)\"\ +\"([^"]*)\"\ +\"([^"]*)\"\ +\"([^"]*)\"\ +\"([^"]*)\"\ +\"([^"]*)\"\ +([0-9]*)} $ad ignore ad lineone linetwo linethree city state zip if {$zip == 0} {set zip ""} {} set comp [expr [string match $city ""]+[string match $state ""]] if {$comp==2}\ {}\ {if {$comp==1}\ {set bridge " " set zip " $zip"}\ {if {$comp==0}\ {set bridge ", " set zip " $zip"}\ {}}} puts $ofh " \\address\{$ad\}\{\%" if {[string match $lineone ""]}\ {puts $ofh "\\mygobble"}\ {puts $ofh " $lineone"} if {[string match $linetwo ""]}\ {}\ {puts $ofh " \\\\$linetwo"} if {[string match $linethree ""]}\ {}\ {puts $ofh " \\\\$linethree"} if {[string match "$city$state$zip" ""]}\ {}\ {puts $ofh " \\\\$city$bridge$state$zip"} puts $ofh " \}" set ad $temp } # Spit out any email addresses associated with this person if {[string match $net nil]} {set net ""} {} regexp {\((\".*\")\)} $net ignore net while {[string match $net ""] == 0} { set temp "" regexp {\"([^"]*)\"(.*)} $net ignore net temp puts -nonewline $ofh "\\url\{$net\}" set net $temp if {[string match $net ""] == 0} {puts $ofh "\\\\"} {puts $ofh ""} } puts $ofh "\}\n" } } # Once everything's finished, we send along the footer while 1 { if {[gets $header line] == -1} break puts $ofh $line } puts "Done." exit % % \end{macrocode} % % \section{\LaTeX{} Style} % We use this to simplify the format file. % \begin{macrocode} %<*style> \NeedsTeXFormat{LaTeX2e}[1995/06/01] \ProvidesClass{filoaddr} [1998/01/17 18:15:06 3.1.1.1 Filofax address pages (Frank Bennett)] \DeclareOption{fourcolumn}% {\PassOptionsToPackage{\CurrentOption}{autofilo}} \DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} \ProcessOptions \LoadClass{article} \RequirePackage{rotating} \RequirePackage{url} % \end{macrocode} % Some variables. % \begin{macrocode} \def\mygobble#1{} \newlength\templen \newlength\mytemplength \newlength\descheight \newlength\myparwidth \newlength\descwidth \newlength\biggerwidth \newlength\myentryheight \newlength\myparheight \newlength\mylinewidth % \end{macrocode} % Define a macro to format each entry. % \begin{macrocode} \def\entry#1{% \vbox{% \vskip2pt \topline \vskip 2pt \parbox{\linewidth}{% \raggedright% \small#1} \vskip 1pt \bottomline}} % \end{macrocode} % The above macro requires a couple of line-building % macros. % \begin{macrocode} \def\topline{% \vbox to0pt{% \hbox to\linewidth{% \hskip-2.4pt% \vrule width0.4pt height0pt depth7pt% \vrule width\mylinewidth depth0.4pt height0pt% \vrule width0.4pt height0pt depth7pt\hskip-2.4pt}% \vskip-7pt}} \def\bottomline{% \vbox to0pt{% \vskip-7pt \hbox to\linewidth{% \hskip-2.4pt% \vrule width0.4pt height7pt depth0pt% \vrule width\mylinewidth depth0.4pt height0pt% \vrule width0.4pt height7pt depth0pt% \hskip-2.4pt}}} % \end{macrocode} % Define a macro to format addresses. % \begin{macrocode} \def\address#1#2{% \settoheight\myparheight{\vbox{% \boxmaxdepth0pt% \parbox{\myparwidth}{\raggedright #2}}}% \settowidth\descwidth{\small\textbf{#1}}% \ifnum\descwidth>\myparheight\biggerwidth\descwidth\else% \biggerwidth\myparheight\fi% \vbox{\vskip3pt% \hbox to\linewidth{% \hskip3pt% \vbox to\biggerwidth{% \vfil% \hbox to\descheight{% \begin{sideways}{\small\textbf{#1}}\end{sideways}% \hfil}% \vfil}% \hskip2pt% \vbox to\biggerwidth{% \vfil% \hbox to\myparwidth{% \parbox{\myparwidth}{\raggedright #2}}% \vfil}}}} % \end{macrocode} % Define an environment that creates frames and sets up % variables for use in the macros we have just defined. % \begin{macrocode} \def\addresses#1{% \autofilo{#1} \settoheight\descheight{\vbox{\boxmaxdepth0pt{\small\textbf{Yy}}}} \myparwidth\linewidth% \advance\myparwidth by-\descheight\relax% \advance\myparwidth by-5pt\relax% \mylinewidth\linewidth \advance\mylinewidth by4pt\relax} \def\endaddresses{\endautofilo} % % \end{macrocode} %\iffalse % \begin{macrocode} %<*installer> \def\batchfile{mkaddr.ins} \input docstrip.tex \keepsilent \preamble \endpreamble \postamble \endpostamble \def\WritePreamble#1{} \def\WritePostamble#1{} \generate{\file{mkaddr.Frank}{\from{mkaddr.dtx}{format}} \file{mkaddr.tcl}{\from{mkaddr.dtx}{script}} \file{.emacs.for.bbdb}{\from{mkaddr.dtx}{elisp}} \file{filoaddr.sty}{\from{mkaddr.dtx}{style}} } \Msg{***********************************************************} \Msg{*} \Msg{* To finish the installation, you have to move the following} \Msg{* file into you executable search path:} \Msg{*} \Msg{* \space\space mkaddr} \Msg{*} \Msg{* And you have to move the following file into the search} \Msg{* used by TeX:} \Msg{*} \Msg{* \space\space filoaddr.sty} \Msg{*} \Msg{***********************************************************} % % \end{macrocode} %\fi % \Finale \PrintChanges