diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/dates/dates.dtx |
Initial commit
Diffstat (limited to 'macros/latex/contrib/dates/dates.dtx')
-rw-r--r-- | macros/latex/contrib/dates/dates.dtx | 2395 |
1 files changed, 2395 insertions, 0 deletions
diff --git a/macros/latex/contrib/dates/dates.dtx b/macros/latex/contrib/dates/dates.dtx new file mode 100644 index 0000000000..430ee85b3b --- /dev/null +++ b/macros/latex/contrib/dates/dates.dtx @@ -0,0 +1,2395 @@ +%\iffalse +% +% File dates.dtx +% Copyright (C) 1996, 1997 by Frank Bennett. All rights reserved. +% +% IMPORTANT NOTICE: +% +% You are not allowed to change this file. You may however copy +% this file to a file with a different name and then change the +% copy if (a) you do not charge for the modified code, (b) you +% acknowledge the author(s) in the new file, if it +% is distributed to others, and (c) you attach these same +% conditions to the new file. +% +% You are not allowed to distribute this file alone. You are not +% allowed to take money for the distribution or use of this file +% (or a changed version) except for a nominal charge for copying +% etc. +% +% You are allowed to distribute this file under the condition that +% it is distributed with all of its contents, intact. +% +% For error reports, or offers to help make this a more powerful, +% friendlier, and altogether more thrilling package, please contact me on +% fb@soas.ac.uk +% +%<*dtx> + \ProvidesFile{dates.dtx} +%</dtx> +%<style>\NeedsTeXFormat{LaTeX2e}[1995/06/01] +%<style>\ProvidesPackage{dates} +%<style> [1997/02/17 v1.3 Dates parsing support (Frank Bennett)] +% \fi +% +% \def\fileversion{v1.3} +% \def\filedate{1997/02/17} +% +% +% \iffalse +%<*driver> +\documentclass{ltxdoc} +%\CodelineIndex +% +%\EnableCrossrefs +\begin{document} +%\OnlyDescription % comment out for implementation details +\DocInput{dates.dtx} +\end{document} +%</driver> +% \fi +% +% \changes{v1.0}{1996/12/10}{Initial version separated from calendar.dtx} +% \changes{v1.0}{1996/12/12}{Overhauled to provide error handling and +% various other features} +% \changes{v1.0}{1996/12/14}{Adapted the plain \TeX{} code for the phases +% of the moon and used it to set it up a function item in a list. It works!} +% \changes{v1.0}{1996/12/14}{Tidied up some sloppiness in the handling of groups. +% No active characters now appear in braced text, and functions no longer +% require square braces. Documentation updated to this effect.} +% \changes{v1.0}{1996/12/15}{Modified toXmac to allow no-frills ranges.} +% \changes{v1.1}{1996/12/27}{Minor bug fixes for final release with the +% Calendar package.} +% \changes{v1.2}{1997/01/18}{Changed gdef of characters in capsdown to +% plain def, so that diacritics and maths will not be screwed up +% by calendar. Capsdown state is fixed by xdef immediately +% before group enclosing the capsdown; definition is in force +% only just before and just after the high-speed read of the +% argument.} +% \changes{v1.2}{1997/01/18}{Fixed a bug that the above fix produced +% in the handling of function definitions.} +% \changes{v1.3}{1997/02/17}{Added code to support recursive dates +% falling on exactly the same day of the month in every month. +% Perhaps such dates should be permitted to conditionally shift to a nearby +% day in the event of a holiday. Perhaps not.} +% +% \title{User's Guide to the Dates package\thanks{This file is version number +% \fileversion{}. It was last revised on +% \filedate.}} +% +% \author{Frank G. Bennett, Jr.\thanks{The code contained in this file just +% provides a smart \LaTeXe front end to +% the \texttt{calendar} macros for \TeX{} that I +% found on CTAN. The \TeX{} macros work quite +% well, but lack any documentation. Their provenance is also a +% mystery. If anyone can tell me who wrote them, I will gladly +% include an acknowledgement in this documentation.}} +% +% \maketitle +% +% \DoNotIndex{\@,\@@par,\@beginparpenalty,\@empty} +% \DoNotIndex{\@flushglue,\@gobble,\@input} +% \DoNotIndex{\@makefnmark,\@makeother,\@maketitle} +% \DoNotIndex{\@namedef,\@ne,\@spaces,\@tempa} +% \DoNotIndex{\@tempb,\@tempswafalse,\@tempswatrue} +% \DoNotIndex{\@thanks,\@thefnmark,\@topnum} +% \DoNotIndex{\@@,\@elt,\@forloop,\@fortmp,\@gtempa,\@totalleftmargin} +% \DoNotIndex{\",\/,\@ifundefined,\@nil,\@verbatim,\@vobeyspaces} +% \DoNotIndex{\|,\~,\ ,\active,\advance,\aftergroup,\begingroup,\bgroup} +% \DoNotIndex{\cal,\csname,\def,\documentstyle,\dospecials,\edef} +% \DoNotIndex{\egroup} +% \DoNotIndex{\else,\endcsname,\endgroup,\endinput,\endtrivlist} +% \DoNotIndex{\expandafter,\fi,\fnsymbol,\futurelet,\gdef,\global} +% \DoNotIndex{\hbox,\hss,\if,\if@inlabel,\if@tempswa,\if@twocolumn} +% \DoNotIndex{\ifcase} +% \DoNotIndex{\ifcat,\iffalse,\ifx,\ignorespaces,\index,\input,\item} +% \DoNotIndex{\jobname,\kern,\leavevmode,\leftskip,\let,\llap,\lower} +% \DoNotIndex{\m@ne,\next,\newpage,\nobreak,\noexpand,\nonfrenchspacing} +% \DoNotIndex{\obeylines,\or,\protect,\raggedleft,\rightskip,\rm,\sc} +% \DoNotIndex{\setbox,\setcounter,\small,\space,\string,\strut} +% \DoNotIndex{\strutbox} +% \DoNotIndex{\thefootnote,\thispagestyle,\topmargin,\trivlist,\tt} +% \DoNotIndex{\twocolumn,\typeout,\vss,\vtop,\xdef,\z@} +% \DoNotIndex{\,,\@bsphack,\@esphack,\@noligs,\@vobeyspaces,\@xverbatim} +% \DoNotIndex{\catcode,\end,\escapechar,\frenchspacing,\glossary} +% \DoNotIndex{\hangindent,\hfil,\hfill,\hskip,\hspace,\ht,\it,\langle} +% \DoNotIndex{\leaders,\long,\makelabel,\marginpar,\markboth,\mathcode} +% \DoNotIndex{\mathsurround,\mbox,\newcount,\newdimen,\newskip} +% \DoNotIndex{\nopagebreak} +% \DoNotIndex{\parfillskip,\parindent,\parskip,\penalty,\raise,\rangle} +% \DoNotIndex{\section,\setlength,\TeX,\topsep,\underline,\unskip,\verb} +% \DoNotIndex{\vskip,\vspace,\widetilde,\\,\%,\@date,\@defpar} +% \DoNotIndex{\[,\{,\},\]} +% \DoNotIndex{\count@,\ifnum,\loop,\today,\uppercase,\uccode} +% \DoNotIndex{\baselineskip,\begin,\tw@} +% \DoNotIndex{\a,\b,\c,\d,\e,\f,\g,\h,\i,\j,\k,\l,\m,\n,\o,\p,\q} +% \DoNotIndex{\r,\s,\t,\u,\v,\w,\x,\y,\z,\A,\B,\C,\D,\E,\F,\G,\H} +% \DoNotIndex{\I,\J,\K,\L,\M,\N,\O,\P,\Q,\R,\S,\T,\U,\V,\W,\X,\Y,\Z} +% \DoNotIndex{\1,\2,\3,\4,\5,\6,\7,\8,\9,\0} +% \DoNotIndex{\!,\#,\$,\&,\',\(,\),\+,\.,\:,\;,\<,\=,\>,\?,\_} +% \DoNotIndex{\discretionary,\immediate,\makeatletter,\makeatother} +% \DoNotIndex{\meaning,\newenvironment,\par,\relax,\renewenvironment} +% \DoNotIndex{\repeat,\scriptsize,\selectfont,\the,\undefined} +% \DoNotIndex{\arabic,\do,\makeindex,\null,\number,\show,\write,\@ehc} +% \DoNotIndex{\@author,\@ehc,\@ifstar,\@sanitize,\@title,\everypar} +% \DoNotIndex{\if@minipage,\if@restonecol,\ifeof,\ifmmode} +% \DoNotIndex{\lccode,\newtoks,\onecolumn,\openin,\p@,\SelfDocumenting} +% \DoNotIndex{\settowidth,\@resetonecoltrue,\@resetonecolfalse,\bf} +% \DoNotIndex{\clearpage,\closein,\lowercase,\@inlabelfalse} +% \DoNotIndex{\selectfont,\mathcode,\newmathalphabet,\rmdefault} +% \DoNotIndex{\bfdefault} +% \setcounter{StandardModuleDepth}{1} +% \DeleteShortVerb{\|} +% \MakeShortVerb{\"} +% +% \begin{abstract} +% \noindent This package provides two low-level macros for the parsing of text +% using \LaTeXe{}. +% \end{abstract} +% +% +% \CheckSum{1737} +% +% \section{Introduction} +% +% This package provides a macro, "\dateread", that can +% be used to parse date strings, either individually +% or recursively. The macro expects a human-readable +% syntax, which it converts into an integer (a ``long +% date'') that can +% be more easily used for some types of computation. +% A set of companion macros and token registers +% is also provided for +% converting long dates into human-readable form. +% +% Dates may be specified either individually, +% or as recursive dates within a range. +% The human-readable syntax for two +% types of recursive date are built +% into the package, but an interface for writing +% specialized extensions in native \LaTeX{} is also provided. +% The handling of parsed dates is also within +% user control; it is defined in a +% single argument fed to "\dateread" when it is invoked +% in front of a list of dates. +% +% This package was +% developed as one of the building blocks of +% the "calendar" package, but is released as a separate +% chunk of code because the date parsing task is a function +% discrete from the work of building a calendar from +% constituent blocks of information (which is the +% main task of the "calendar" package proper). +% If other applications are found for this package, +% that is all to the good. Put my name on it, +% let me know, and we'll have a drink together sometime. +% +% This user guide is brief, because the parser is +% flexible enough that a long catalogue of strictures +% is unnecessary. The next section describes the syntax +% for entering dates. It is followed by a brief description +% of how the macro can be called upon in another package, +% and notes on extending the parser to provide enhanced +% functionality. I have also provided guidance notes +% in the code itself. +% +% \InputIfFileExists{datesynt} +% {} +% {\PackageError{calendar} +% {Unpack dates.dtx before printing these docs.} +% {}} +% +% +% \section{Calling the Parser} +% +% As mentioned above, the short description in curly +% braces can only contain plain text. Printing of +% variable text (such as the text of the date) is +% done through the argument to the "\dateread" macro. +% This argument is an action that will be performed +% once after each date in the list is read. The +% date and the description text may be included by +% using the appropriate commands. These are: +% +% \begin{tabular}{ll} +% "\theyear" & The year (four digits).\\ +% "\themonth" & The full name of the month.\\ +% "\theshortmonth" & The name of the month (3 characters).\\ +% "\themonthnumber" & The number of the month.\\ +% "\theday" & The day of the month.\\ +% "\thetimestart" & Starting time for an item.\\ +% "\thetimeend" & Ending time for an item.\\ +% "\theweekday" & The name of the day of the week.\\ +% "\theshortweekday" & Abbreviated day of the week (3 characters).\\ +% "\theshorttext" & The text describing the date.\\ +% "\thelongtext" & A longer description of the date.\\ +% "\thelongdate" & The long date (an integer).\\ +% "\thedays" & The maximum number of days this month.\\ +% \end{tabular} +% +% You can also call up information using lower-level +% registers and macros that contain date-related +% information. Go to the code and commentary +% section for further details. +% +% The demonstration file included in this package +% lists dates on the terminal using the "\message" +% command. In a more serious application, text can +% be printed, stored to registers or boxes, or +% sent in pre-processed form to an external file. +% +% The following is a valid invocation of the +% macro: +% +% \begin{quote} +% \begin{verbatim} +% \dateread{% +% \message{% +% \theweekday, % +% \theday\space% +% \themonthname\space% +% \theyear}} +% % +% % The list of dates to be parsed +% % +% June 15 1997 {Summer Holiday Begins} +% September 25 1997 {Summer Holiday Ends} +% January 1 1997 {First day of January} +% February 18 1997 {Frank's Birthday} +% Every Monday at 2:00 {Go to the Beach} +% Every 20 {20th day of the month} +% % +% % The end of the list. +% % +% \relax{} +% \end{verbatim} +% \end{quote} +% +% A style package that uses the date parser +% should of course conceal stretches of code +% like that above from the end user. If lists +% of dates are maintained in separate files, you +% can do something like the following, +% +% \begin{quote} +% \begin{verbatim} +% \def\readinput{% +% \dateread{\message{\theweekday^^J}}} +% +% \def\inputandread{% +% \expandafter\readinput% +% \@@input \filename\relax{} +% } +% \end{verbatim} +% \end{quote} +% +% \noindent where "\filename" contains the name of a file +% to be read. One would then confirm the existence +% of the file, then run "\inputandread". +% +% \section{Extending the Parser} +% +% When the parser is used in a package, it may be +% necessary to modify its behaviour to perform +% special actions in the course of processing. +% For example, you may want to provide a facility +% for setting the range in files containing +% recursive dates from a single file so that, +% say, an academic schedule can be moved forward +% to the next year without a lot of typing. +% This kind of effect can be achieved by defining a +% word which diverts processing to a macro that +% performs the desired action before continuing +% to digest the list of dates. +% +% The flow of processing can be diverted at two +% points: +% +% \begin{enumerate} +% \item Immediately after a word is read; +% or +% \item Immediately after a date and its +% text have been digested. +% \end{enumerate} +% +% The parser can be +% re-entered in any of three states: +% +% \begin{enumerate} +% \item One that +% looks for the next word in a date string; +% \item One that digests the description text; or +% \item One +% that completes the processing of a date +% entry and its text. +% \end{enumerate} +% +% Each of the exit points and reentry states is +% associated with a macro name. Diversion is +% accomplished by defining a word that "\let"s the +% exit macro name be the user's own macro. Reentry +% is accomplished in the user's macro by ending +% with the appropriate macro name. The names +% the macros to use as exit points are, +% in the order of the first list above: +% +% \begin{enumerate} +% \item "\dates@@@read" +% \item "\dates@read@exit" +% \end{enumerate} +% +% The names of macros to use for reentry +% states are: +% +% \begin{enumerate} +% \item "\dates@@@read@default" +% \item "\dates@@@@read@default" +% \item "\dates@read@exit@default" +% \end{enumerate} +% +% An extension therefore consists of a user-defined +% macro, and a user-defined word that invokes +% "\let" as appropriate. Words should be padded +% to exactly three characters using "X", and should +% be appended with the suffix "mac". The following +% defines a word, "if", which sets a toggle and +% continues parsing a date: +% +% \begin{quote} +% \begin{verbatim} +% \newif\ifusedif +% +% \def\myownmacro{% +% \usediftrue% +% \dates@@@read@default} +% +% \def\ifXmac{% +% \let\dates@@@read=\myownmacro} +% \end{verbatim} +% \end{quote} +% +% This is the same method used in the package +% itself to provide recursive dates and the +% function entry type; see the code commentary section +% for less trivial examples. +% +%\StopEventually{\PrintIndex} +% +% \section{The Macros} +% +% \subsection{External Utilities} +% +% \begin{macro}{\@ifoverword} +% +% A macro for breaking strings into words is provided by +% a package distributed separately. +% +% \begin{macrocode} +%<*style> +\RequirePackage{overword} +% \end{macrocode} +% \end{macro} +% +% \subsection{The Engine Core} +% +% \begin{macro}{\dateread} +% \begin{macro}{\date@read} +% \begin{macro}{\date@@read} +% \begin{macro}{\date@@@read} +% \begin{macro}{\@gobble@enditalls} +% +% The interface macro starts by setting "\dates@action" +% to be its first argument. It then opens with the initialization +% of variables that are zeroed only at the start of a run +% of dates, and passes control to the next macro in the chain. +% At this point dates are unsorted, so an alternative +% format such as HTML should \textit{not} be generated +% by the argument text, unless you have a filter for sorting +% the text after \TeX{} exits. In normal use, +% events should be sorted and selected +% first, in the package that calls +% "dates.sty". The argument can be used to choose +% between modes of \LaTeX{} handling, however. For example, +% you might want to export the text to a file, or +% store it directly into a list macro. By inserting a "\let" +% into the hook in "\dates@analyze", you can put toggles +% into the event files themselves. This is used in "calendar" +% to provide for the selective ``freezing'' of events files +% in a pre-processed form. +% +% \begin{macrocode} +\long\gdef\dateread#1{% + \csname dates@reset@longtext\endcsname% + \let\dates@read\dates@read@default% + \gdef\dates@action{#1}% + \def\dates@subranges{}% + \dates@subrange@start=0% + \dates@subrange@end=0% + \dates@read} +% \end{macrocode} +% +% The next macro continues with initialization, and +% makes uppercase characters active inside a group. +% Square braces are made grouping characters, so that +% when the next chained macro runs +% and grabs everything up to the next curly brace, +% we will have a means of grouping within the +% grabbed text. Square braces will be used for +% grouping in user-defined functions for the automatic +% generation of dates. +% +% \begin{macrocode} +\long\gdef\dates@read@default{% + \dates@time@start=0% + \dates@time@end=0% + \setyear{1900}% + \dates@month=0% + \dates@day=0% + \dates@weekd@target=7% + \def\theshorttext{}% + \def\thelongtext{}% + \dates@suppressfalse% + \global\let\dates@init\relax% + \global\let\dates@increment\relax% + \let\dates@@@read=\dates@@@read@default% + \let\dates@@@@read=\dates@@@@read@default% + \let\dates@read@exit=\dates@read@exit@default% + \bgroup% + \dates@capsdown% + \dates@@read} +% \end{macrocode} +% +% Once we have the text with the catcodes set appropriately, +% we cut off the catcode change and run a macro in front of +% the gobbled text which will chew it up while looping. +% The "\enditall" terminator is a misnomer, really; it +% ends the parsing of a single date, but we will continue +% parsing until "\end" or "\relax{}" are encountered. +% +% \begin{macrocode} +\long\def\dates@@read#1#{% + \let\end\relax% + \xdef\cal@temp{#1 }% + \egroup% + \expandafter\dates@@@read\cal@temp\enditall} +% \end{macrocode} +% +% The following macro does the chewing. The macro +% "\dates@analyze" will alter the values of +% "\dates@@@read" and of "\dates@read@exit" +% to achieve special effects. Any hooks that +% redefine these functions should chain to +% their defaults, which end in "@default". +% +% \begin{macrocode} +\def\dates@@@read@default{% + \@ifoverword\enditall% + {\expandafter\dates@analyze\@overword{}% + \@gobble@enditalls}% + {\expandafter\dates@analyze\@overword{}% + \dates@@@read}% + {\expandafter\dates@analyze\@overword{}% + \ifnum\dates@year>0% If date exists, process + \let\dates@read\relax% ... and expire + \dates@read@exit% May be a range, so not default + \fi% + \expandafter\end\@gobbletwo}}% +% \end{macrocode} +% +% Package extensions that import files on the fly may +% produce multiple "\enditall"s in the scan text for +% a date. This will chomp all of them. The change involves +% introducing the following macro via the second +% argument to "\@ifoverword", above. +% \changes{v1.1}{1996/12/21}{Added handler for multiple enditall's.} +% +% \begin{macrocode} +\def\@gobble@enditalls#1{% + \@ifnextnparchar\enditall% + {\let\next\@gobble@enditalls% + \next}% + {\dates@@@@read}% + {\message{This can't happen}}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Selective Handling} +% +% \subsubsection{Defaults} +% +% There are three points at which special handling can +% be spliced into the parsing routine. Below, the defaults +% are presented first, followed by alternatives that are +% built into the package. Other special handling routines +% can be spliced in, as discussed below under \ref{analyze}. +% +% \begin{macro}{\dates@@@@read} +% \begin{macro}{\dates@@@@@read} +% +% The following will read arguments (one mandatory +% argument in curly braces, one optional one in square +% braces) and save them for +% use as text descriptions applying to the date. +% After the arguments are stored, we +% chain to the exit routine that will perform the action +% that the user gave to "\dateread". +% +% There are some dirty tricks here involving the square +% brace. We define the macro globally inside a group, +% so that our catcode change will not affect other +% code. Then we set the open brace to be a grouping +% character like "{". We can't use this inside the +% definition directly (because \TeX{} will try to keep reading +% text until it finds the matching brace), so we "\let" +% a macro have this token's value. The "\let" is +% global because the value of "{" is global. +% Then we use the funny brace macro inside the +% definition to look for a square brace coming up. +% +% All of this jiggery-pokery is necessary because +% the "\futurelet" command (used by "\@ifnextchar") will stamp +% a category code on the brace when it sees it. +% The end result, though, is that \TeX{} will +% read all the way to the last closing square +% brace, not just to the next one it finds. +% Any square braces inside the text will disappear +% in printed text, but at least the user will not +% find the style blowing up in his face. +% +% We also make capital letters active, with "\dates@capsdown". +% This is done in a separately nested group, so that +% it can be turned off before reading any square-braced +% text, without affecting the catcode of the braces. +% +% \begin{macrocode} +\bgroup + \catcode`\[=1 + \global\let\dates@funny@brace=[ + \gdef\dates@@@@read@default#1{% + \def\theshorttext{#1}% + \bgroup% + \catcode`\[=1\catcode`\]=2\relax% + \bgroup% + \dates@capsdown% + \@ifnextnparchar\dates@funny@brace% + {\egroup% + \dates@@@@@read}% + {\egroup% + \egroup% + \dates@read@exit}% + {\egroup% + \egroup% + \dates@read@exit}} +\egroup +% \end{macrocode} +% +% The optional argument uses bog-standard \LaTeX{} +% option syntax. The only wrinkle is in the +% catcode changes invoked within a group in the +% macro above. These are cut off here. +% +% \begin{macrocode} +\def\dates@@@@@read#1{% + \egroup% + \iflongtext% + \def\thelongtext{#1}% + \fi% + \dates@read@exit} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% The following is the default value of "\dates@read@exit". +% It fixes the date and rationalizes the registers +% containing human-readable date information, and +% saves the date for future reference (i.e.~in case +% we need it as the bottom end of a range). +% It then performs the action given by the user in the +% argument to "\dates@read", and chains back to continue +% parsing within the presented list of dates. +% +% \begin{macrocode} +\def\dates@read@exit@default{% + \dates@fix% + \caldate% + \dates@lastdate\dates@date% + \ifdates@suppress@global% + \else% + \ifdates@suppress% + \else% +% \bgroup% +% \dates@capsup% + \dates@action% +% \egroup% + \fi% + \fi% + \dates@read} +% \end{macrocode} +% +% \subsubsection{Recursive Handling} +% +% \begin{macro}{\dates@read@exit@range} +% +% This is meant to be spliced into the parser immediately +% before the macro: +% +% \begin{quote} +% "\dates@read@exit@default" +% \end{quote} +% +% It is invoked +% by the word "to" in the current date entry. Invoked +% after the text argument describing the current date +% has been grabbed, it begins by rationalizing the machine +% and human readable dates. It then expands the registers +% containing the starting and ending long dates describing +% a range into a list macro. The dates are stepped down one +% and up one day respectively, so that a simple ">" or "<" +% will tell us whether a given date is within a subrange. +% The list macro will later +% be used as a series of bounds +% in the generation of recursive dates and dates +% defined by a function. +% +% \begin{macrocode} +\def\dates@read@exit@range{% + \dates@fix% + \caldate% + \dates@subrange@end\dates@date% + \dates@reg=\expandafter{\dates@subranges}% + \edef\dates@subranges{% + \the\dates@reg% + \noexpand\delim{\the\dates@subrange@start}% + {\the\dates@date}}% + \let\dates@read@exit\dates@read@exit@default% + \dates@read@exit} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dates@read@exit@recurse} +% \begin{macro}{\dates@read@exit@@recurse} +% \begin{macro}{\dates@read@exit@@@recurse} +% +% This is the generic routine for generating dates according +% to a recursively invoked formula. It is also intended +% for splicing in in front of the macro: +% +% \begin{quote} +% "\dates@read@exit@default" +% \end{quote} +% +% The first macro in this chain checks +% to be sure that a list of ranges exists. +% It then defines the macro used to delimit the list +% to something that will recurse within a subrange. +% The list macro is then dumped into the document +% for complete expansion. When it finishes, +% control is passed back to the top, so that +% reading can continue through the list of dates. +% +% \begin{macrocode} +\def\dates@read@exit@recurse{% + \expandafter\ifcat\expandafter$\dates@subranges$% + \PackageError{dates}{No range given}% + {You need to specify a range before % + recursive entries and formulae}% + \fi\relax% + \ifx\dates@init\relax% + \ifnum\dates@day>0\relax + \dates@everymonth@day\dates@day% + \global\let\dates@init\dates@init@monthly@dom% + \global\let\dates@increment\dates@increment@monthly@dom% + \else% + \PackageError{dates}{Incomplete recursive entry}% + {You need to specify a day of the week or a day of % + the month or something for entries beginning with % + the word Every.} + \fi% + \fi% + \let\delim\dates@read@exit@@recurse% + \dates@subranges% + \dates@read} +% \end{macrocode} +% +% This is the macro to which "\delim" is set above. +% It sets up registers with the top and bottom boundaries +% of the range, as given in the list, then sets the +% current date to be the bottom of the range. +% It then executes an (arbitrary) function to find +% the first calculated date above the bottom of the range, +% rationalizes the human-readable date registers, and +% performs the user's requested action. It then chains to +% the macro that will loop until the range is exceeded. +% +% \begin{macrocode} +\def\dates@read@exit@@recurse#1#2{% + \dates@subrange@start#1\relax% + \dates@subrange@end#2\relax% + \global\dates@date=\dates@subrange@start\relax% + \caldate% + \dates@init% + \caldate% + \ifdates@suppress@global% + \else% + \ifdates@suppress% + \else% +% \bgroup% +% \dates@capsup% + \dates@action% +% \egroup% + \fi% + \fi% + \let\next\dates@read@exit@@@recurse% + \dates@read@exit@@@recurse} +% \end{macrocode} +% +% This is the macro that does the actual recursion for recursive entries. +% It increments, checks the date, performs the action if appropriate, +% otherwise breaks the loop so that control can pass back to +% "\dates@read@exit@recurse". +% +% \begin{macrocode} +\def\dates@read@exit@@@recurse{% + \dates@increment\relax% + \ifnum\dates@date<\dates@subrange@end\relax% + \caldate% + \ifdates@suppress@global% + \else% + \ifdates@suppress% + \else% + \dates@action% + \fi% + \fi% + \else% + \let\next\relax% + \fi% + \next} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dates@increment@daily} +% \begin{macrocode} +\def\dates@increment@daily{% + \global\advance\dates@date by 1\relax} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dates@init@weekly} +% \begin{macro}{\dates@increment@weekly} +% +% The following is the initialization macro for weekly recursion. +% It moves to the first instance of the targetted +% day of the week above the bottom of the subrange. +% +% \begin{macrocode} +\def\dates@init@weekly{% + \mod7\dates@date\dates@weekd% + \dates@three=\dates@weekd@target\relax% + \advance\dates@three by -\dates@weekd\relax% + \ifnum\dates@three<0\relax% + \advance\dates@three by7% + \fi% + \global\advance\dates@date by \dates@three\relax} +% \end{macrocode} +% +% This is the increment macro used for weekly recursion. +% It just bumps up the date seven days each time it is invoked. +% +% \begin{macrocode} +\def\dates@increment@weekly{% + \global\advance\dates@date by7\relax} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dates@init@monthly@dow} +% \begin{macro}{\dates@increment@monthly@dow} +% +% The following is the general initialization macro for finding +% an instance of a day of the week within a month. It begins +% by setting the value of a macro with which it terminates +% to be "\relax", in the hope that a match will be found +% the first time it is invoked. We then move the date +% forward, if necessary, to find the targetted day of the week. +% When this is found, we set the human-readable register +% information according to that long date (including the +% day of the month). Dividing and multiplying by "7" yields +% the largest multiple of "7" that is equal to or less than the +% day of the month. If this is "0", we're in the first week, +% if "7" we're in the second, and so forth. If the value +% of the current day is too low, we move up the date. +% If it is too high, we move to the first day +% of the next month, and request a loop back through +% the same routines. +% +% \begin{macrocode} +\def\dates@init@monthly@dow{% + \let\dates@init@monthly@dow@recurse\relax% + \nextday\dates@weekd@target% + \caldate% + \dates@one\dates@day% + \divide\dates@one by 7\relax% + \multiply\dates@one by 7\relax% + \ifnum\dates@modulo>\dates@one\relax% + \dates@two\dates@modulo% + \advance\dates@two by -\dates@one% + \global\advance\dates@date by \dates@two% + \else% + \ifnum\dates@modulo<\dates@one\relax% + \dates@next@month% + \let\dates@init@monthly@dow@recurse\dates@init@monthly@dow% + \fi% + \fi% +\dates@init@monthly@dow@recurse} +\def\dates@init@monthly@dom{% + \let\dates@init@monthly@dom@recurse\relax% + \ifnum\dates@day>\dates@everymonth@day% + \dates@next@month% + \let\dates@init@monthly@dom@recurse\dates\init@monthly@dom% + \else% + \dates@day\dates@everymonth@day% + \dates@fix% + \fi% + \dates@init@monthly@dom@recurse} +% \end{macrocode} +% +% This is the general incrementing macro for monthly entries. +% It's pretty simple; we just move to the first day of the +% next month, then run the initialization macro again to +% find the appropriate date within the month. +% +% \begin{macrocode} +\def\dates@increment@monthly@dow{% + \dates@next@month% + \dates@init@monthly@dow} +\def\dates@increment@monthly@dom{% + \dates@next@month% + \dates@init@monthly@dom} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dates@@@@read@function} +% \begin{macro}{\dates@@@@read@@function} +% +% This is designed to be spliced into the parser +% immediately before the macro: +% +% \begin{quote} +% "\dates@@@@read@default". +% \end{quote} +% +% It is invoked, like the other special handling routines, +% via the "\dates@execute" hook in the text analyzer +% (see \ref{analyze} for details). It reads two +% arguments immediately following the word that +% triggers it. It stores these for reference. +% The third argument is read after checking to be +% sure that we have reached the end of the parsing +% string, and are looking at the delimiter that +% ends it. Then this is gobbled, and dumped into the +% document so that the definitions it contains will +% take effect. The jiggery-pokery with grouping +% limits the effect of "\makeatletter" to the +% scope of the braces delimiting the user's +% function definition, while the macros he defines +% there can be defined locally. +% +% This third argument should not produce any printed output, and should define, +% at minimum, two macros, the names of which are given as +% the first and second arguments following the invoking +% word in the parsed text. The first of these will +% initialize to the first date conforming to the formula, +% counting from the bottom of a range of dates, and should +% return a long date in "\dates@date". The second should +% increment upward one date from a given date, also returning +% the result in "\dates@date". The demonstration file +% contains a sample of code which calculates the phases of +% the moon. +% +% \begin{macrocode} +\long\def\dates@@@@read@function #1 #2 {% + \edef\dates@init{\csname#1\endcsname}% + \edef\dates@increment{\csname#2\endcsname}% + \@ifnextnparchar\enditall% + {\bgroup% + \makeatletter% + \expandafter\dates@@@@read@@function\@gobble}% + {\PackageError% + {dates}% + {Extra text after function names}% + {The third argument must be in curly braces.}}% + {\relax}} +% \end{macrocode} +% +% \begin{macrocode} +\long\def\dates@@@@read@@function#1{% + \long\gdef\dates@temp{#1}% + \egroup% + \dates@temp% + \let\dates@temp\relax% + \dates@@@@read@default} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{The Analyzer} +% +% Human-readable dates are fetched word by word by +% the above routines. The "\dates@@@read@default" +% macro feeds individual words to the analyzer +% described here. +% +% \begin{macro}{dates@analyze} +% +% This +% is a pretty straightforward set of nested +% conditions that will uniquely identify an item +% as a month, a year, a day or a time, and respond +% accordingly. The macro is somewhat long, so +% comments are provided to indicate nesting +% levels and their functions. +% +% \begin{macrocode} +\long\def\dates@analyze#1#2#{% +% \end{macrocode} +% +% \begin{description} +% \item[Level One] Check to see if we're dealing with a number. +% If so, define a macro containing only zero to use in a series of +% parsing checks. +% \end{description} +% +% \begin{macrocode} + \ifcat\noexpand#11% + \def\dates@zero{0}% +% \end{macrocode} +% +% \begin{description} +% \item[Level Two] Check to see if this is is not a range of times. +% \end{description} +% +% \begin{macrocode} + \expandafter\dates@check@hyphen\@overword-{}% + \ifx\dates@arg@b\dates@zero% +% \end{macrocode} +% +% \begin{description} +% \item[Level Three] It now looks like this either a lone time or +% an integer. Check to see if it's not a time. (We use "\@overword", +% but it will have the same content as "\dates@arg@a"). +% \end{description} +% +% \begin{macrocode} + \expandafter\dates@check@colon\@overword:{}% + \ifx\dates@arg@b\dates@zero% +% \end{macrocode} +% +% \begin{description} +% \item[Level Four] Alright, so it's an integer. That means it's either a year +% or a day of the month. The instructions require a 4-digit +% year, which is always larger than a day of the month. +% \end{description} +% +% \begin{macrocode} + \expandafter\ifnum\@overword>31% + \setyear{\dates@arg@a}% + \else% + \ifnum\dates@day>0% + \dates@dayerror% + \else% + \global\dates@day=\dates@arg@a% + \fi% + \fi% +% \end{macrocode} +% +% \begin{description} +% \item[Level Three (again)] If the item was a lone time, we set variables +% accordingly. +% \end{description} +% +% \begin{macrocode} + \else% + \expandafter\dates@strip@colon\dates@arg@b% + \global\dates@time@start=\dates@arg@a% + \multiply\dates@time@start by 60% + \advance\dates@time@start by \dates@arg@b% + \global\dates@time@end=\dates@time@start% + \fi% +% \end{macrocode} +% +% \begin{description} +% \item[Level Two (again)] If it was a range of times, we have the +% extremes of the range in "\dates@arg@a" and "\dates@arg@b". +% We process each so that a colon delimiter is not required, +% but will be recognized if given. Note the "0" in the definition +% of "\dates@check@colon" et al., above; this produces a default of zero +% if this is a bare number with no colon delimiter. +% +% We proceed by first setting aside the contents of "\dates\arg@b" +% so that they will not be overwritten. We then check for the +% existence of a colon and, if one is found, the trailing +% colon left by the test macro is stripped off. We then +% set the time. +% \end{description} +% +% \begin{macrocode} + \else% + \expandafter\dates@strip@hyphen\dates@arg@b% + \let\dates@temp\dates@arg@b% + \expandafter\dates@check@colon\dates@arg@a:{}% + \ifx\dates@arg@b\dates@zero% + \else% + \expandafter\dates@strip@colon\dates@arg@b% + \fi% + \dates@time@start=\dates@arg@a\relax% + \multiply\dates@time@start by 60\relax% + \global\advance\dates@time@start by \dates@arg@b\relax% +% \end{macrocode} +% +% \begin{description} +% \item[Level Two (continued)] We then do exactly the same thing for the second time +% given. +% \end{description} +% +% \begin{macrocode} + \expandafter\dates@check@colon\dates@temp:{}% + \ifx\dates@arg@b\dates@zero% + \else% + \expandafter\dates@strip@colon\dates@arg@b% + \fi% + \dates@time@end=\dates@arg@a\relax% + \multiply\dates@time@end by 60\relax% + \global\advance\dates@time@end by \dates@arg@b% + \fi% +% \end{macrocode} +% +% \begin{description} +% \item[Level one (again)] \label{analyze} If "\dates@word" does not look like a +% number, then it is handled as text. +% We pass control to a macro that will +% simply execute a macro name derived from the first three +% characters of the word. If it's unknown chaff, it will therefore +% effectively be ignored. This can be used as a hook +% for defining options not included in the "dates" package +% proper. The description of the hooks used by the +% vanilla version of "dates" is given below. +% \end{description} +% +% \begin{macrocode} + \else% + \dates@execute#1#2XXX{}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dates@execute} +% +% Used as the default action in the analyzer, this just blindly +% executes a macro that may match a day, month or option +% name. If the date string is limited by "\relax{}", +% the macro name "\relax" will be read in as a token +% for interpretation. To prevent unexpected results, +% we therefore convert a leading control sequence to a string +% within "\csname" "\endcsname". We must not give +% the same treatment to non-control-sequence items, +% however, because this would prevent the expansion of +% uppercase characters, which have been read in as active +% characters, to their lowercase counterparts. An "\ifcat" +% is used to choose which action is appropriate. The +% macros invoked by "\dates@execute" never take arguments, +% so they can be expanded within the scope of "\ifcat". +% +% \begin{macrocode} +\def\dates@execute#1#2#3#4#{% + \ifcat#1\relax% + \expandafter\csname% + \string#1#2#3mac\endcsname% + \else% + \expandafter\csname#1#2#3mac\endcsname% + \fi}% +% \end{macrocode} +% \end{macro} +% +% \subsection{Fodder for the Analyzer} +% +% As can be gleaned from an examination of "\dates@execute", +% a word is read by executing a macro named using +% its first three letters. We provide definitions +% for a number of such macros here. +% +% \begin{macro}{\evemac} +% +% "Every" sets up for recursion, and for a default of +% incrementing over days of the week. +% +% \begin{macrocode} +\def\evemac{% + \global\let\dates@read@exit=\dates@read@exit@recurse} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\daymac} +% +% The following was suggested by Miroslav Novak: +% +% \begin{macrocode} +\def\daymac{% + \global\let\dates@increment=\dates@increment@daily} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\othmac} +% +% "Other" will modify the effect of "every" to +% choose every other date within the range. You +% can't choose the starting dates within the +% subrange --- but some automation is better than none. +% +% \begin{macrocode} +\def\othmac{% + \global\let\dates@increment=\dates@increment@semiweekly} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\firmac} +% \begin{macro}{\secmac} +% \begin{macro}{\thimac} +% +% "First", "second" and "third" will set a counter than controls which +% instance of a day of the week within a month should be chosen, +% and modifies the effect of "every" to recurse on that +% instance within every month, within the subrange. +% \begin{macrocode} +\def\firmac{% + \dates@modulo=0% + \global\let\dates@init=\dates@init@monthly@dow% + \global\let\dates@increment=\dates@increment@monthly@dow}% +% +\def\secmac{% + \dates@modulo=7% + \global\let\dates@init=\dates@init@monthly@dow% + \global\let\dates@increment=\dates@increment@monthly@dow}% +% +\def\thimac{% + \dates@modulo=14% + \global\let\dates@init=\dates@init@monthly@dow% + \global\let\dates@increment=\dates@increment@monthly@dow}% +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\1stmac} +% \begin{macro}{\2ndmac} +% \begin{macro}{\3rdmac} +% +% These are just aliases of the macros above. +% +% \begin{macrocode} +\expandafter\let\csname1stmac\endcsname=\firmac% +\expandafter\let\csname2ndmac\endcsname=\secmac% +\expandafter\let\csname3rdmac\endcsname=\thimac% +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\toXmac} +% +% The following responds to "to" in the parsed text. If +% the year is zero, it sets +% the bottom of a range to the last date encountered, and +% lets the exit macro for processing a finished date be +% one which will set the top of the range before performing +% the action specified by the user. +% If the year is greater than zero, we grab the \textit{current} +% date, reset everything to zero, and continue parsing. +% This permits ``no frills'' range designations, as +% in the "calendar" package. +% +% The "X" is appended to +% fill out to three characters. For reasons that I do not +% fully understand, this was necessary to prevent the +% package from exiting within the scope of a group. +% +% \begin{macrocode} +\def\toXmac{\relax% + \ifnum\dates@year=0% + \dates@subrange@start\dates@lastdate% + \else% + \dates@fix% + \dates@subrange@start\dates@date% + \dates@month=0% + \dates@day=0% + \setyear{1900}% + \fi% + \let\dates@read@exit\dates@read@exit@range}% + % \end{macrocode} +% \end{macro} +% +% \begin{macro}{\funmac} +% +% The following causes a function definition to be read +% immediately after the word "function" in the date text. +% +% \begin{macrocode} +\def\funmac{% + \global\let\dates@read@exit=\dates@read@exit@recurse% + \global\let\dates@@@read=\dates@@@@read@function} +% \end{macrocode} +% \end{macro} +% +% The following causes the suppression of any action +% in respect of the entry in which it is found. +% +% \begin{macrocode} +\def\remmac{% + \global\dates@suppresstrue} +% \end{macrocode} +% +% \begin{macro}{\janmac} +% \begin{macro}{\jancheckmac} +% +% The months are defined globally using a recursive engine +% that is discarded when the macros have been defined. +% Each month macro first sets a counter to the number of +% days in the month, so that a range check can be performed +% when the date is interpreted. It then checks to +% see if a month has already been selected, and if so +% it forces a fatal error; otherwise, the month counter +% is set to the appropriate value. +% +% \begin{macrocode} +\bgroup + \def\monthdata#1#2#3#4#5\end{% + \expandafter\gdef\csname#2#3#4mac\endcsname{% + \ifnum\dates@month>0% + \dates@montherror% + \else% + \global\dates@month=#1% + \fi}% + \ifcat$#5$\let\next\@gobble\else\let\next\monthdata\fi% + \next#5\end}% +% \end{macrocode} +% +% +% The following does the action generation of month macros. +% \begin{macrocode} + \monthdata1jan2feb3mar4apr5may6jun% + 7jul8aug9sep{10}oct{11}nov{12}dec\end +\egroup +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\monmac} +% +% Days of the week are specified in a similar fashion. +% +% \begin{macrocode} +\bgroup + \def\weekdata#1#2#3#4#5\end{% + \expandafter\gdef\csname #2#3#4mac\endcsname{% + \ifnum\dates@weekd@target<7\relax% + \dates@weekerror% + \else% + \global\dates@weekd@target=#1\relax% + \ifx\dates@increment\relax% + \global\let\dates@init\dates@init@weekly% + \global\let\dates@increment\dates@increment@weekly% + \fi% + \fi}% + \ifcat$#5$\let\next\@gobble\else\let\next\weekdata\fi% + \next#5\end} + + \weekdata0sun1mon2tue3wed4thu5fri6sat\end +\egroup +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dates@montherror} +% \begin{macro}{\dates@weekerror} +% \begin{macro}{\dates@dayerror} +% +% These three macros are used in the above definitions +% to produce error messages if something is wrong +% with a date. +% +% \begin{macrocode} +\def\dates@montherror{% + \PackageError{dates}{Month multiply defined}{% + You have set the month more than once here.}} +% +\def\dates@dayerror{% + \PackageError{dates}{Day multiply defined}{% + You have set the day more than once here.}} +% +\def\dates@weekerror{% + \PackageError{dates}{Week multiply defined}{% + You have set the day of the week more than once here.}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Low-level Bits and Pieces} +% +% \begin{macro}{\dates@capsdown} +% +% The "\lowercase" function provided in \TeX{} does not +% operate in \TeX{}'s mouth, and so cannot be used to +% create lowercase strings for export to a non-DVI +% file or for display on the terminal. +% We can get around this problem by +% making all upper-case characters +% active, and defining them to lowercase themselves. The +% operative definition is "\dates@capsdown". +% The +% grouping culls the bootstrapping definitions used to +% create these macros from memory. A detailed explanation +% these macros is not given here, but they do work. +% Essentially, they function by looping over sets of three +% characters, two uppercase and one lowercase, building a +% macro ("\dates@capsdown") that will make the uppercase +% characters in the list locally active, with the appropriate +% definition. Two uppercase characters are required in the +% list because on is read to identify the character so +% that it can be made active in order, on the second read, +% to take its active form and define it. +% +% \begin{macrocode} +\bgroup +\newtoks\dates@reg +\dates@reg={} +\def\dates@capsdown{} +\def\dates@capsup{} +\def\dates@capsactive#1{% + \ifx#1\end% + \let\next\relax% + \else% + \catcode`#1=13% + \let\next\dates@@capsactive% + \fi% + \next} +\def\dates@@capsactive#1#2{% + \dates@reg=\expandafter{% + \dates@capsdown\catcode`#1=13\def#1{#2}}% + \xdef\dates@capsdown{\the\dates@reg}% + \dates@reg=\expandafter{% + \dates@capsup\edef#1{\string#1}}% + \xdef\dates@capsup{\the\dates@reg}% + \let\next\dates@capsactive% + \next} +\dates@capsactive% + AAaBBbCCcDDdEEeFFfGGgHHhIIiJJjKKk% + LLlMMmNNnOOoPPpQQqRRrSSsTTtUUuVVv% + WWwXXxYYyZZz\end +\egroup +% \end{macrocode} +% \end{macro} +% +% For parsing strings, we use some little +% macros to identify strings that have a colon in +% them (which will be assumed to be a time) +% or a hyphen (assumed to be a range of times), +% and to strip those off where necessary. +% +% \begin{macrocode} +\def\dates@check@colon#1:#2#{% + \def\dates@arg@a{#1}% + \def\dates@arg@b{0#2}} +\def\dates@strip@colon#1:{% + \def\dates@arg@b{#1}} +\def\dates@check@hyphen#1-#2#{% + \def\dates@arg@a{#1}% + \def\dates@arg@b{0#2}} +\def\dates@strip@hyphen#1-{% + \def\dates@arg@b{#1}} +% \end{macrocode} +% +% The following macro is used to terminate +% processing. +% +% \begin{macrocode} +\expandafter\expandafter\expandafter\def% + \expandafter\csname% + \string\relaxXXmac\endcsname{% + \let\dates@@@@read\relax} +% \end{macrocode} +% +% +% +% \subsection{Interface Macros for Date Info} +% +% \begin{macro}{\theyear} +% \begin{macro}{\themonth} +% \begin{macro}{\theshortmonth} +% \begin{macro}{\themonthnumber} +% \begin{macro}{\theday} +% \begin{macro}{\theweekday} +% \begin{macro}{\theshortweekday} +% \begin{macro}{\thelongdate} +% \begin{macro}{\themonthdays} +% \begin{macro}{\theshorttext} +% \begin{macro}{\thelongtext} +% +% \label{interface} These macros can be used to include date information +% in the text fed to "\dateread". They do not contain +% unprintable operations, and so can be used to display +% text on the terminal as well as in a document. All +% are updated from the long date by the "\caldate" command. +% The macros "\theshorttext" and "\thelongtext" are +% defined elsewhere on the fly; token registers cannot +% be used for these because they must be allowed to +% expand fully on the terminal. +% +% \begin{macrocode} +\def\theyear{\the\dates@year@full} +\def\themonth{\the\dates@monthname} +\def\theshortmonth{\the\dates@monthname} +\def\themonthnumber{\the\dates@month} +\def\theday{\the\dates@day} +\def\theweekday{\the\dates@dayname} +\def\theshortweekday{\the\dates@shortweekday} +\def\thelongdate{\the\dates@date} +\def\themonthdays{\the\dates@days} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Maths Functions for Dates} +% +% The following code is an almost direct rip-off of the +% "calendar" macros for plain \TeX{} that are stored on +% CTAN. If anyone knows who the author is, I will be happy +% to include a credit here. I have made scant effort +% to document the code, but it works well. +% +% \begin{macro}{\setyear} +% +% Set the current year. +% +% \begin{macrocode} +\def\setyear#1{\dates@year=#1% + \advance\dates@year by -1900\calculateyearbase} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\nextyear} +% +% Advance by one year +% +% \begin{macrocode} +\def\nextyear{\advance\dates@year by1% + \calculateyearbase} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dates@next@month} +% Advance by one month. +% +% \begin{macrocode} +\def\dates@next@month{% + \ifnum\dates@month=12% + \advance\dates@year by 1\calculateyearbase% + \dates@month=1% + \dates@day=1% + \else% + \advance\dates@month by 1% + \dates@day=1% + \fi% + \dates@fix\caldate} +% \end{macrocode} +% \end{macro} +% +% Set the current time zone. +% +% \begin{macro}{\settimezone} +% \begin{macrocode} +\def\settimezone#1{\dates@timezone=#1% + \multiply\dates@timezone by 1000% + \divide\dates@timezone by24} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calculateyearbase} +% +% Set the "\ifleapyear" toggle. Set "\dates@yearbase" to the number of +% days passed from 1900, Jan 0 to New year's date in the target year. +% +% \begin{macrocode} +\def\calculateyearbase{% + \dates@yearbase=-1% + {\count0=\dates@year\divide\count0 by4% + \multiply\count0 by4\relax% + \ifnum\dates@year=\count0% + \global\dates@catch=0% + \else% + \global\dates@catch=1% + \fi}% + \ifcase\dates@catch \leapyeartrue\or% + \leapyearfalse\fi% + {\count0=\dates@year\multiply\count0% + by1461\advance\count0 by3% + \divide\count0 by4% + \global\dates@catch=\count0}% + \global\advance\dates@yearbase by\dates@catch\relax% + \ifnum\dates@year=0\global\dates@yearbase=0\leapyearfalse\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\monthdays} +% +% Set the number of days passed at the end of each month in "\dates@day". +% +% \begin{macrocode} +\def\monthdays{% +\global\dates@catch\ifcase\dates@month% + 0\or31\or% + 59\or90\or120\or151\or181\or212\or% + 243\or273\or304\or334\or365\fi% + {\ifleapyear\ifnum\dates@month>1% + \global\advance\dates@catch by1\fi\fi}% + \dates@day=\dates@catch} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dates@fix} +% +% Return the long date of "\dates@month", "\dates@day" in the year "\dates@year" +% in "\dates@date" after checking to be sure that the month and the day +% have been set, if confirmation has been toggled on, and that +% the number of days +% in the month conforms to the constraints of reality. +% +% \begin{macrocode} +\def\dates@fix{% + \ifnum\dates@month=0% + \ifdates@requiremonth% + \PackageError{dates}{Missing month}{% + You need to specify a date for the month in this date entry.}% + \else% + \dates@month=1% + \fi% + \fi% + \ifnum\dates@day=0% + \ifdates@requireday% + \PackageError{dates}{Missing day of the month}{% + You need to specify a day of the month in this date entry.}% + \else% + \dates@day=1% + \fi% + \fi% + \dates@monthname@get% + \ifnum\dates@days<\dates@day% + \PackageError{dates}{Day of month out of range}{% + There are only \the\dates@days\space days in % + \themonth, but you have tried^^J% + to specify \the\dates@day.}% + \else% + \dates@date=\dates@day{\advance\dates@month by-1% + \monthdays% + \advance\dates@date by\dates@day% + \global\advance\dates@date by\dates@yearbase}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod} +% +% Long date MOD 7 will give the week day. +% Sunday is 0 and Saturday is 6. The base +% number is returned in "\dates@three". +% +% \begin{macrocode} +\def\mod#1#2#3{\dates@three=#2\relax% + \dates@four=\dates@three% + \divide\dates@three by #1% + \multiply\dates@three by #1% +\advance\dates@four by -\dates@three% + #3=\dates@four} + +\def\dates@year@get{% + \dates@year@full\dates@year% + \global\advance\dates@year@full by 1900\relax} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\theweekday} +% +% Set the names of week day (Local). +% +% \begin{macrocode} +\def\dates@dayname@get{% + \mod7\dates@date\dates@weekd% + \ifcase\dates@weekd% + \global\dates@dayname{Sunday}% + \global\dates@shortweekday{Sun}% + \or \global\dates@dayname{Monday}% + \global\dates@shortweekday{Mon}% + \or \global\dates@dayname{Tuesday}% + \global\dates@shortweekday{Tue}% + \or \global\dates@dayname{Wednesday}% + \global\dates@shortweekday{Wed}% + \or \global\dates@dayname{Thursday}% + \global\dates@shortweekday{Thu}% + \or \global\dates@dayname{Friday}% + \global\dates@shortweekday{Fri}% + \or \global\dates@dayname{Saturday}% + \global\dates@shortweekday{Sat}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\caldate} +% +% Gives the usual calendar date for +% a long date in counter "\dates@date". +% Returned in "\dates@day", "\dates@month" and "\dates@year" +% and other registers. See the interface macros above +% under \ref{interface}. +% +% \begin{macrocode} +\def\caldate{\dates@year=\dates@date% + \multiply\dates@year by4\divide\dates@year by1461% + \calculateyearbase% + {\advance\dates@date by-\dates@yearbase\dates@month=0% + \loop\monthdays\ifnum\dates@day<\dates@date% + \global\advance\dates@month by1\repeat% + {\advance\dates@month by-1\monthdays% + \advance\dates@date by-\dates@day% + \global\dates@day=\dates@date}}% + \dates@year@get% + \dates@monthname@get% + \dates@dayname@get} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dates@monthname@get} +% +% This stores the names of the months to registers. +% It is run by "\caldate". +% +% \begin{macrocode} +\def\dates@monthname@get{% + \ifcase\dates@month% + \or \global\dates@monthname{January}% + \global\dates@shortmonthname{Jan}% + \global\dates@days=31\relax% + \or \global\dates@monthname{February}% + \global\dates@shortmonthname{Feb}% + \ifleapyear% + \global\dates@days=29\relax% + \else% + \global\dates@days=28\relax% + \fi% + \or \global\dates@monthname{March}% + \global\dates@shortmonthname{Mar}% + \global\dates@days=31\relax% + \or \global\dates@monthname{April}% + \global\dates@shortmonthname{Apr}% + \global\dates@days=30\relax% + \or \global\dates@monthname{May}% + \global\dates@shortmonthname{May}% + \global\dates@days=31\relax% + \or \global\dates@monthname{June}% + \global\dates@shortmonthname{Jun}% + \global\dates@days=30\relax% + \or \global\dates@monthname{July}% + \global\dates@shortmonthname{Jul}% + \global\dates@days=31\relax% + \or \global\dates@monthname{August}% + \global\dates@shortmonthname{Aug}% + \global\dates@days=31\relax% + \or \global\dates@monthname{September}% + \global\dates@shortmonthname{Sep}% + \global\dates@days=30\relax% + \or \global\dates@monthname{October}% + \global\dates@shortmonthname{Oct}% + \global\dates@days=31\relax% + \or \global\dates@monthname{November}% + \global\dates@shortmonthname{Nov}% + \global\dates@days=30\relax% + \or \global\dates@monthname{December}% + \global\dates@shortmonthname{Dec}% + \global\dates@days=31\relax% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\nextday} +% +% Find the next (previous) day after +% (before) "\dates@date" with "\mod7=#1". +% +% \begin{macrocode} +\def\nextday#1{{\count0=#1\mod7\dates@date\dates@weekd% + \advance\count0 by-\dates@weekd\relax% + \ifnum\count0<0\advance\count0 by7\fi% + \global\advance\dates@date by\count0}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prevday} +% +% \begin{macrocode} +\def\prevday#1{\snextday#1% + \global\advance\dates@date by-7} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snextday} +% +% \begin{macrocode} +\def\snextday#1{\global\advance\dates@date by1% + \nextday#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sprevday} +% +% \begin{macrocode} +\def\sprevday#1{\global\advance\dates@date by-1% + \prevday#1} +% \end{macrocode} +% \end{macro} +% +% Convert from Julian date and time in +% \date to long date (in local time) +% +% \begin{macrocode} +\def\jdttol{\advance\dates@date by500% + \advance\dates@date by\dates@timezone\divide\dates@date by1000} +% \end{macrocode} +% +% \subsection{Trigonometric Functions} +% +% \begin{macrocode} +\def\sintable#1{\ifcase #1 0\or100\or199% + \or296\or389\or479\or565\or644\or717% + \or783\or841\or891\or932\or964\or985% + \or997\or1000\or992\or974\or946\or909% + \or863\or808\or746\or675\or598\or516% + \or427\or335\or239\or141\or42\or-58% + \or-158\fi} +% \end{macrocode} +% +% Reduces modulo "2\pi" (requires positive +% argument theta): +% "theta := theta" "MOD 2\pi", where +% "theta = count1*10^(-3)" +% +% \begin{macrocode} +\def\twopimod{\count2 =\count1% + \divide\count2 by6284 \count3 =1853% + \count4 =6283\multiply\count3 by\count2% + \multiply\count4 by\count2% + \divide\count3 by10000% + \advance\count3 by\count4% + \advance\count1 by-\count3}% +% \end{macrocode} +% +% "v := sin(theta)", where +% "v = count4*10^(-3)"; +% "theta = count1*10^(-3)" +% theta is reduced "MOD 2\pi" to be +% "0<=theta<2\pi" by "\TWOPIMOD", +% then linear interpolation is performed +% using "\SINTABLE". +% +% \begin{macrocode} +\def\sin{\relax% + \ifnum\count1<0 \signtrue% + \count1=-\count1\else \signfalse\fi% + \loop\ifnum\count1>6284\twopimod\repeat\relax% + \ifnum\count1>3142% + \advance\count1 by-3142% + \ifsign\signfalse\else\signtrue\fi\fi% + \multiply\count1 by10\count3=\count1% + \divide\count3 by1000\count2=\count3% + \multiply\count3 by1000% + \advance\count3 by-\count1 % + \count5 =\sintable{\count2 }% + \count4 =\count5\advance\count2 by1% + \advance\count4 by -\sintable{\count2}% + \multiply\count4 by\count3% + \divide\count4 by1000% + \advance\count4 by\count5% + \ifsign\count4 =-\count4\fi}% +% \end{macrocode} +% +% "v := cos(theta)", where +% "v = count4*10^(-3)"; +% "theta = count1*10^(-3)". +% "\SIN" is evaluated on "pi/2-theta". +% \begin{macrocode} +\def\cos{\advance\count1 by-1571% + \multiply\count1 by-1\sin}% +% \end{macrocode} +% Linear transformation of T giving +% "theta := a*T+b", where +% "T = count0*10^(-6)"; +% "theta = count1*10^(-3)"; +% "a = #1*10^3+#2+#3*10^(-3)"; +% "b = #4*10^(-3)" +% +% \begin{macrocode} +\def\lin#1.#2.#3+#4.{\count1=#3% + \count2=#2\count3=#1% + \multiply\count1 by\count0% + \multiply\count2 by\count0\relax% + \multiply\count3 by\count0% + \divide\count1 by1000% + \advance\count1 by\count2% + \divide\count1 by1000% + \advance\count1 by\count3% + \advance\count1 by #4\relax} +% \end{macrocode} +% +% Accumulate value returned by a +% trigonometric function, scaled by +% factor f, into count6: +% "ac := ac+f*v", where +% "ac = count6*10^(-7)" +% "v = value" of "SIN" or "COS =count4*10^(-3)" +% "f = #1*10^(-4)" +% +% \begin{macrocode} +\def\fac#1{\multiply\count4 by #1% + \advance\count6 by\count4} +\def\id{\count4=\count1} % Identity +% \end{macrocode} +% +% \subsection{Initialization} +% +% This initializes +% "\uselongtext" to the value selected by the user +% in the package calling "dates". +% \begin{macrocode} +\def\dates@initialize@longtext{% + \ifuselongtext% + \def\dates@reset@longtext{% + \longtexttrue}% + \else% + \def\dates@reset@longtext{% + \longtextfalse}% + \fi} +% \end{macrocode} +% +% Before anything further is executed, the following registers +% and macros need to be in place. +% +% \begin{macrocode} +\newcount\dates@year +\newcount\dates@timezone +\dates@timezone=0 +\newcount\dates@catch +\newcount\dates@day +\newcount\dates@everymonth@day +\newcount\dates@month +\newcount\dates@date +\newcount\dates@one +\newcount\dates@two +\newcount\dates@three +\newcount\dates@four +\newcount\dates@weekd +\newcount\dates@time@start +\newcount\dates@time@end +\newcount\dates@subrange@start +\newcount\dates@subrange@end +\newcount\dates@days +\newcount\dates@lastdate +\newcount\dates@yearbase +\newcount\dates@weekd@target +\newcount\dates@modulo +\newcount\dates@year@full +\newcount\dates@extra@day +\newtoks\dates@reg +\newtoks\dates@dayname +\newtoks\dates@shortweekday +\newtoks\dates@monthname +\newtoks\dates@shortmonthname +\newif\iflongtext +\longtexttrue +\newif\ifdates@requiremonth +\newif\ifdates@requireday +\newif\ifdates@suppress +\newif\ifdates@suppress@global +\newif\ifleapyear +\let\delim\relax +\def\enditall{END IT ALL} +\def\dates@empty{} +%</style> +% \end{macrocode} +% +% \section{The Demo File} +% +% \begin{macrocode} +%<*demo> +\documentclass{minimal} +\usepackage{dates} +\begin{document} + +\makeatletter + +%<demo>% +%<demo>% We invoke the \dateread command. +%<demo>% +\dateread +%<demo>% +%<demo>% We tell it to report a few details to the terminal. +%<demo>% +{\message{\theshorttext}% + \message{\theday/\the\dates@month/\the\dates@year}% + \ifx\thelongtext\dates@empty% + \else% + \message{\thelongtext}% + \fi} +%<demo>% +%<demo>% The following are ranges. +%<demo>% + december 10 1995 {^^JStart of First} +to jan 10 1996 {End of First} + december 10 1996 {^^JStart of Second} +to jan 10 1997 {End of Second^^J} +%<demo>% +%<demo>% The following are specific dates (obviously) +%<demo>% +February 18 1997 {^^JFrank's Next Birthday} + [The best presents come in small packages.^^JIt + would be a terrific present for someone to make + this one smaller.] +February 18 1998 {^^JFrank's Next Birthday But One} +%<demo>% +%<demo>% These are a couple of recursive dates. +%<demo>% +Every Monday {^^JMonday Coffee} +Every Third Tuesday {^^JMeeting} +% +%<demo>% Here is a sample function definition, which gives +%<demo>% the phases of the moon within the ranges. The code +%<demo>% was ripped off from the calendar package for plain +%<demo>% TeX +%<demo>% + +function \moonsinit \moonsincrement + + { + \newcount\moonno + \newif\ifsign + + \def\firstmoon{\moonno=\dates@year + \multiply\moonno by123685 + \divide\moonno by10000 + \multiply\moonno by4\advance\moonno by-1 + \loop\moondate\relax + \ifnum\dates@date<\dates@subrange@start + \advance\moonno by1\repeat} + +%<demo>% Compute date for cycle quarter MOONNO + + \def\moondate{{\count0=\moonno + \lin 202.126.369+0.\count0=\count1 + \count6=0 + \lin 0.2.319+2907.\sin\fac{3} + \divide\count6 by1000 + \lin 365.249.86+7593.\id\fac{1} + \divide\count6 by10\count7 =\count6 + \ifodd\moonno\quarters + \else\fullornew\fi\global\dates@date=\count7} + \jdttol} + +%<demo>% Correction for full and new moon + + \def\fullornew{\count6=0 + \lin -393.0.0+0. + \divide\count1 by100000000 + \advance\count6 by\count1 + \lin 0.628.300+6269.\sin + \multiply\count6 by\count4 + \lin -7.-700.-369+ 928.\sin\fac{ -74} + \lin 0. 628. 300+ 6269.\sin\fac{ 1734} + \lin 1. 256. 600+12539.\sin\fac{ 21} + \lin 8. 328. 670+ 5341.\sin\fac{-4068} + \lin 8. 538. 220+-4597.\sin\fac{ 10} + \lin 8. 956. 970+11610.\sin\fac{ -51} + \lin 16. 238. 589+-5526.\sin\fac{ -4} + \lin 16. 657. 340+10682.\sin\fac{ 161} + \lin 16. 866. 890+ 743.\sin\fac{ 104} + \lin 17. 285. 640+16951.\sin\fac{ 50} + \lin 17. 495. 190+ 7013.\sin\fac{ 4} + \lin 24. 986. 10+16023.\sin\fac{ -4} + \lin 25. 195. 560+ 6084.\sin\fac{ -6} + \divide\count6 by10000 + \advance\count7 by\count6 } + +%<demo>% Correction for quarters + + \def\quarters{\lin -393.0.0+0. + \divide\count1 by100000000 + \count6 =\count1 \lin 0.628.300+6269. + \sin\multiply\count6 by\count4 + \lin -16. -29. -40+-4413.\sin\fac{ 40} + \lin -7.-700.-369+ 928.\sin\fac{ -47} + \lin -7. -72. -69+ 7198.\sin\fac{ -30} + \lin 0. 628. 300+ 6270.\sin\fac{ 1721} + \lin 1. 256. 600+12539.\sin\fac{ 21} + \lin 8. 328. 670+ 5341.\sin\fac{-6280} + \lin 8. 538. 220+-4598.\sin\fac{ 21} + \lin 8. 956. 970+11611.\sin\fac{ -119} + \lin 16. 238. 589+-5526.\sin\fac{ -4} + \lin 16. 657. 340+10682.\sin\fac{ 89} + \lin 16. 866. 890+ 743.\sin\fac{ 79} + \lin 17. 285. 640+16952.\sin\fac{ 3} + \lin 17. 495. 190+ 7013.\sin\fac{ 3} + \lin 24. 986. 10+16023.\sin\fac{ -4} + \lin 25. 195. 560+ 6085.\sin\fac{ -6} + \count8=\count6\count6=28000 + \lin 628. 300. 373+ 6270.\cos\fac{ -4} + \lin 8. 328. 670+ 5341.\cos\fac{ 3} + \count2=\moonno + \advance\count2 by-1\divide\count2 by2 + \ifodd\count2\multiply\count6 by-1 \fi + \advance\count6 by\count8 + \divide\count6 by10000 + \advance\count7 by\count6 } + +%<demo>% Events for phases. +%<demo>% Uses PHASE (local). + + \def\phase{{\count0=\moonno + \count1=\moonno + \divide\count0 by4\multiply\count0 by4 + \advance\count1 by-\count0\relax + \global\edef\themoon{\ifcase\count1 + New Moon\or First Quarter\or + Full Moon\or Last Quarter\fi}}} + + \gdef\moonsinit{% + \firstmoon + \dates@month=12\dates@day=31\dates@fix\advance\dates@date by1 + \count1=\dates@date + \moondate + \phase + \caldate} + + \gdef\moonsincrement{% + \advance\moonno by 1 + \moondate\phase + \caldate} + + } + {\themoon} + +\end{document} +%</demo> +% \end{macrocode} +% +%\iffalse +% \begin{macrocode} +%<syntax>% \section{Date Syntax} +%<syntax>% +%<syntax>% \subsection{General Rules} +%<syntax>% +%<syntax>% The rules themselves are explained here first. If you +%<syntax>% want to cut to the chase, have a look at the examples +%<syntax>% and experiment a bit with the demo file. It's all +%<syntax>% pretty straightforward. +%<syntax>% +%<syntax>% The parser is indifferent to extra spaces and blank +%<syntax>% lines in dates. It will read a string word by word, +%<syntax>% and classify each word as a time, a day of the month, +%<syntax>% the name of a month, a year or a special function. +%<syntax>% With two exceptions, strings beginning in a number must not mix numbers and +%<syntax>% other characters --- this will produce a low-level +%<syntax>% error from \TeX, and at the moment I can't think of +%<syntax>% an economical way of protecting against this. +%<syntax>% +%<syntax>% Any string +%<syntax>% beginning in a number is interpreted as either a +%<syntax>% time, a day of the month or a year. A string +%<syntax>% containing a colon (the ":" character) is assumed +%<syntax>% to be a time of day. "AM" and "PM" are not recognized; +%<syntax>% you should use 24-hour format when specifying +%<syntax>% times. A numeric string containing a hyphen is assumed +%<syntax>% to be a range of times. In this instance, a colon +%<syntax>% is not necessary if the time is given in whole-hours. +%<syntax>% Pure numeric strings are construed as a day of the month +%<syntax>% if less than 32, or as a year if greater than 31. +%<syntax>% +%<syntax>% Character strings are interpreted on the basis of their +%<syntax>% first three characters; the rest are ignored. Case is +%<syntax>% also irrelevant. Months and days of the week (used for +%<syntax>% defining recursive dates, described below) as well as certain +%<syntax>% special functions are specified as character strings. +%<syntax>% Any word that does not match an existing function +%<syntax>% will be ignored. +%<syntax>% +%<syntax>% Dates are always terminated by a short description +%<syntax>% of the date, which must be in curly braces. +%<syntax>% The description should contain plain text only; +%<syntax>% do not put macros (like "\LaTeX") here. +%<syntax>% +%<syntax>% Dates will be processed until "\dateread" encounters +%<syntax>% "\end{<"\meta{environment name}">}", or the string +%<syntax>% "\relax{}". At the "\end" of an environment, +%<syntax>% the processing of the current date will be completed, +%<syntax>% and the "\end" will be executed. "\relax{}" will +%<syntax>% cause processing to end silently without doing +%<syntax>% anything on the last item (which is the "\relax{}" itself). +%<syntax>% +%<syntax>% \subsection{Specific Dates} +%<syntax>% +%<syntax>% Applying the above rules, the following is a valid +%<syntax>% list of dates. The use of "\dateread" is explained +%<syntax>% below. +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% \begin{verbatim} +%<syntax>% \begin{quote} +%<syntax>% \dateread{\message{\theshorttext}} +%<syntax>% Jan 1 1996{New Year's Day} +%<syntax>% 1 January 1996 at 10:00 +%<syntax>% {New Year Bash}"\\ +%<syntax>% 1996 +%<syntax>% jan 1 8-20:30 +%<syntax>% {New Year Cleaning. Rats.}" +%<syntax>% \end{quote} +%<syntax>% \end{verbatim} +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% Note that the parser is indifferent to word order, +%<syntax>% and that commas should not be used to separate +%<syntax>% words.\footnote{In fact, commas do no harm if +%<syntax>% they follow a string of three or more letters, but +%<syntax>% it is best to keep things simple and clean.} +%<syntax>% +%<syntax>% \subsection{Recursive Dates} +%<syntax>% +%<syntax>% \subsubsection{Ranges} +%<syntax>% +%<syntax>% Any recursive dates (such as "Every" "Monday") must +%<syntax>% be preceded by one or more range specifications, +%<syntax>% which fix the time period or periods within which to +%<syntax>% recurse. +%<syntax>% A range is simply two specific dates separated by the +%<syntax>% word "to". You may specify multiple ranges; +%<syntax>% effect will be given to each of them individually. +%<syntax>% +%<syntax>% The following is a valid range specification: +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% \begin{verbatim} +%<syntax>% February 1 1996 {Start First Period} +%<syntax>% to April 1 1996 {End First Period} +%<syntax>% November 3 1996 {Start Second Period} +%<syntax>% to December 24 1996 {End Second Period} +%<syntax>% \end{verbatim} +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% \subsubsection{Shorthand Dates} +%<syntax>% +%<syntax>% Three types of recursive date can be entered in a +%<syntax>% human-readable syntax. Entries of all types +%<syntax>% begin with the word "every". To put an event +%<syntax>% on every occurence of a day of the week within +%<syntax>% a specified set of subranges, simply indicate the day +%<syntax>% of the week, followed by a short description +%<syntax>% in curly braces. +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% \begin{verbatim} +%<syntax>% Every Monday {Monday!} +%<syntax>% \end{verbatim} +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% To put an event at 14-day intervals, beginning +%<syntax>% with the first occurrence of a specified day +%<syntax>% of the week within each subrange, add the +%<syntax>% word "other". +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% \begin{verbatim} +%<syntax>% Every other Monday 7:00 {Monday Morning Exercise} +%<syntax>% \end{verbatim} +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% To place an event on the "N"th occurrence of +%<syntax>% a specified day of the week within each month, within +%<syntax>% subrange, add "first", "second" or "third". +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% \begin{verbatim} +%<syntax>% Every third Monday 8:00-9:00 +%<syntax>% {Monday Morning Meeting} +%<syntax>% \end{verbatim} +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% To place an event on the same day (as opposed to +%<syntax>% day of the week) in every month, just put the +%<syntax>% number of that day after "every": +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% \begin{verbatim} +%<syntax>% Every 20 {Mortgage payment} +%<syntax>% \end{verbatim} +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% \subsubsection{Suppressing the Action} +%<syntax>% +%<syntax>% There are two ways of suppressing the user-defined action. +%<syntax>% To quickly comment out an entry, put the word "rem" in +%<syntax>% front of it. The date will be read, but the action +%<syntax>% in the argument to "\dateread" will not be performed. +%<syntax>% This can be used, for example, to suppress the appearance +%<syntax>% of a range in the output text. +%<syntax>% +%<syntax>% The second method uses a toggle, and is meant for use by +%<syntax>% style authors. Setting: +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% "\dates@suppress@globaltrue" +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% \noindent will cause the user action to be suppressed +%<syntax>% throughout the invocation of "\dateread". In order for +%<syntax>% the action to be performed on the next invocation, +%<syntax>% the toggle must be set to "false" in the external +%<syntax>% code that calls the parser. +%<syntax>% +%<syntax>% \subsubsection{Functions} +%<syntax>% +%<syntax>% It is possible to specify dates within the subranges +%<syntax>% using an arbitrary formula. Entries of this type +%<syntax>% begin with the word "function". This is followed +%<syntax>% by two control strings, a block of \LaTeX{} code in +%<syntax>% curly braces, and the usual short description, also in +%<syntax>% curly braces. +%<syntax>% +%<syntax>% The first control string is the name of a +%<syntax>% user-defined macro that will find the position +%<syntax>% of the first desired date after the start of the +%<syntax>% range. The second is the name of a macro to +%<syntax>% use in incrementing afterward. The block of +%<syntax>% \LaTeX{} code contains the definitions of these +%<syntax>% and any subsidiary macros. +%<syntax>% +%<syntax>% The following will place an entry on every date within +%<syntax>% the specified subranges. +%<syntax>% +%<syntax>% \begin{quote} +%<syntax>% \begin{verbatim} +%<syntax>% Function \myinit \myincrement +%<syntax>% {\def\myinit{% +%<syntax>% \dates@date=\dates@subrange@start} +%<syntax>% \def\myincrement{% +%<syntax>% \advance\dates@date by 1\relax} +%<syntax>% } +%<syntax>% {A Day} +%<syntax>% \end{verbatim} +%<syntax>% \end{quote} +%<syntax>% +%<syntax>% See the code commentary section of the Dates package for information +%<syntax>% on macros that can be used for manipulating dates. +% \end{macrocode} +% +% \section{The Installation File} +% \begin{macrocode} +%<*installer> +\def\batchfile{dates.ins} +\input docstrip.tex + +\keepsilent + +\preamble + +This file is part of the Dates package. +Copyright (C) 1996, 1997 Frank Bennett, Jr. +All rights reserved. +------------------------------------------ +This is a generated file. + +IMPORTANT NOTICE: + +You are not allowed to change this file. You may however copy +this file to a file with a different name and then change the +copy if (a) you do not charge for the modified code, (b) you +acknowledge the author(s) in the new file, if it +is distributed to others, and (c) you attach these same +conditions to the new file. + +You are not allowed to distribute this file alone. You are not +allowed to take money for the distribution or use of this file +(or a changed version) except for a nominal charge for copying +etc. + +You are allowed to distribute this file under the condition that +it is distributed with all of its contents, intact. + +For error reports, or offers to help make this a more powerful, +friendlier, and better package, please contact me on +`fb' at soas.ac.uk + +\endpreamble + +\generate{\file{dates.sty} {\from{dates.dtx}{style}} + } + +\preamble + +This file is part of the Dates package, +Copyright (C) 1996, 1997 Frank Bennett, Jr. +All rights reserved. +------------------------------------------ +This file is provided for demonstration purposes; feel free +to edit it in any way whatsoever. +------------------------------------------ + + + +\endpreamble + +\postamble +\endpostamble + +\generate{\file{demo.tex}{\from{dates.dtx}{demo}} + } + +\preamble +\endpreamble + +\let\WritePreamble\@gobble +\let\WritePostamble\@gobble + +\generate{\file{datesynt.tex}{\from{dates.dtx}{syntax}} + } + +\Msg{***********************************************************} +\Msg{*} +\Msg{* To finish the installation, you have to move the following} +\Msg{* file into a directory searched by TeX:} +\Msg{*} +\Msg{* \space\space dates.sty} +\Msg{*} +\Msg{***********************************************************} +} +%</installer> +% \end{macrocode} +%\fi +% \Finale \PrintChanges |