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/calendar/dates.dtx |
Initial commit
Diffstat (limited to 'macros/latex/contrib/calendar/dates.dtx')
-rw-r--r-- | macros/latex/contrib/calendar/dates.dtx | 2630 |
1 files changed, 2630 insertions, 0 deletions
diff --git a/macros/latex/contrib/calendar/dates.dtx b/macros/latex/contrib/calendar/dates.dtx new file mode 100644 index 0000000000..5cc1205b08 --- /dev/null +++ b/macros/latex/contrib/calendar/dates.dtx @@ -0,0 +1,2630 @@ +%\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 +% +%<style>\NeedsTeXFormat{LaTeX2e}[1995/06/01] +%<style>\ProvidesPackage{dates} +%<style> [1998/01/17 17:12:39 3.1 Dates parsing support (Frank Bennett)] +%\fi +% +% \def\fileversion{3.1} +% \def\filedate{1998/01/17 17:12:39} +% +%\iffalse +%<*driver> +\documentclass{ltxdoc} +%\CodelineIndex +%\RecordChanges +%\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/21}{Added handler for multiple enditall's.} +% \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.} +% \changes{v1.4}{1997/03/01}{Large number of variable made +% global, to prevent consumption of \TeX{} save space during +% large runs. Task not yet complete, but hardiness much +% improved.} +% \changes{v1.4}{1997/03/01}{Cleanup of documentation; cut out +% all user-level instructions in favour of a cross-reference +% to user-level packages.} +% \changes{v1.4}{1997/03/02}{Inserted fix for broken \texttt{othmac} support.} +% \changes{v1.5}{1997/03/06}{Added initialization \texttt{let} to +% definition of \texttt{daymac} to fix a bug reported by Miroslav +% Novak.} +% \changes{v1.5}{1997/03/06}{Fixed algorithm for ending subranges +% in recursive entries --- was ending one day too soon always.} +% \changes{v1.6}{1997/05/19}{Added language option. Initial language +% support covers English and Japanese.} +% \changes{v1.6}{1997/05/20}{German support added. Thanks due to +% Christian Horn.} +% \changes {v1.7}{1997/06/10}{Removed Japanese option --- far too +% cumbersome to maintain.} +% \changes{v1.8}{1997/10/18}{New public release of all styles +% and modules incorporating global bug-fixes.} +% \changes{v1.9}{1997/10/24}{Eliminated the final (touch wood!) +% cross-nested variable bug. Should run find on small \TeX's now.} +% \changes{v1.10}{1997/10/25}{Eliminated need for bogus entries +% to protect against reads past end of file. } +% \changes{v1.11}{1997/10/26}{Added support for anniversaries.} +% +%\iffalse +% Source tree moved under RCS +% --------------------------- +% dates.dtx,v +% Revision 3.1 1998/01/17 17:12:39 root +% Release code +% +% Revision 2.15 1998/01/17 06:10:58 root +% *** empty log message *** +% +% Revision 2.14 1998/01/17 04:54:44 root +% *** empty log message *** +% +% Revision 2.13 1998/01/16 11:41:21 root +% *** empty log message *** +% +% Revision 2.12 1998/01/16 11:39:57 root +% *** empty log message *** +% +% Revision 2.11 1998/01/16 11:18:23 root +% *** empty log message *** +% +% Revision 2.10 1998/01/16 11:00:58 root +% *** empty log message *** +% +% Revision 2.9 1998/01/16 09:26:26 root +% *** empty log message *** +% +% Revision 2.8 1998/01/16 09:03:04 root +% *** empty log message *** +% +% Revision 2.7 1998/01/15 23:34:12 root +% *** empty log message *** +% +% Revision 2.6 1998/01/15 23:30:14 root +% *** empty log message *** +% +% Revision 2.5 1998/01/15 21:42:28 root +% *** empty log message *** +% +% Revision 2.4 1998/01/15 21:38:26 root +% Trivial change. +% +% Revision 2.3 1998/01/15 21:35:30 root +% First shot at proper language support. +% +% Revision 2.2.1.1 1997/11/07 11:16:06 root +% Eliminated \@gobble from \dates@@@read@@function. +% +% Revision 2.2 1997/11/07 10:44:05 root +% Release code. +% +% Revision 2.1.1.22 1997/11/05 07:40:27 root +% Confirming a string of changes implementing multi-argument +% (aka multi-lingual) support. +% +% Revision 2.1.1.21 1997/11/05 07:37:09 root +% *** empty log message *** +% +% Revision 2.1.1.20 1997/11/05 07:35:42 root +% *** empty log message *** +% +% Revision 2.1.1.19 1997/11/05 07:19:49 root +% *** empty log message *** +% +% Revision 2.1.1.18 1997/11/05 07:14:39 root +% *** empty log message *** +% +% Revision 2.1.1.17 1997/11/05 07:06:09 root +% *** empty log message *** +% +% Revision 2.1.1.16 1997/11/05 06:55:18 root +% *** empty log message *** +% +% Revision 2.1.1.15 1997/11/05 06:46:48 root +% *** empty log message *** +% +% Revision 2.1.1.14 1997/11/05 06:44:42 root +% *** empty log message *** +% +% Revision 2.1.1.13 1997/11/05 06:43:27 root +% *** empty log message *** +% +% Revision 2.1.1.12 1997/11/05 06:41:21 root +% *** empty log message *** +% +% Revision 2.1.1.11 1997/11/05 06:37:42 root +% Backed off from adding new macro. Trying nesting of +% \@ifnextnparchar. +% +% Revision 2.1.1.10 1997/11/05 06:29:43 root +% Added calls to new macro \@ififnextnparchar, to cope +% with possibility of bent brace without following square +% brace. +% +% Revision 2.1.1.9 1997/11/04 21:29:48 root +% Added prototype code for picking up extra entries +% +% Revision 2.1.1.8 1997/11/04 19:52:15 root +% Moved the assignment to \dates@date to the top of +% \dates@init@weekly. Careless error. +% +% Revision 2.1.1.7 1997/11/04 14:57:40 root +% Fixed local assignments of \dates@date and \dates@catch +% accidentally included in patch code. +% +% Revision 2.1.1.6 1997/11/04 14:45:10 root +% Re-applied patches to cope with the common recursive entries, +% now that the code for "every other" has made it necessary to +% move the assignment to \dates@date out of the common code +% for recursive entries. +% +% Revision 2.1.1.5 1997/11/04 08:25:42 root +% Fixed silly typing error in fix just applied. +% +% Revision 2.1.1.4 1997/11/04 08:23:08 root +% Moved downcasing code directly into \dates@execute +% +% Revision 2.1.1.3 1997/11/04 07:39:27 root +% Added missing ` to \dates@downcase +% +% Revision 2.1.1.2 1997/11/04 07:33:08 root +% Eliminated \capsdown from the code, installed new routine +% based on character constants and \cs{ifcase}. +% +% Revision 2.1.1.1 1997/11/04 05:06:07 root +% Development branch +% +% Revision 2.1 1997/11/01 15:08:09 bennett +% Release code. +% +% Revision 1.17.0.8 1997/11/01 14:29:11 root +% *** empty log message *** +% +% Revision 1.17.0.7 1997/11/01 13:28:54 root +% Range limit trap suspended for the present; this needs careful +% consideration, so that the "freeze" declaration is not rendered +% useless or unpredictable. +% +% Revision 1.17.0.6 1997/11/01 12:50:18 root +% Alterations to recursion routines broke anniversaries. Rewritten. +% Also added optional counter \dates@range@limit, which cuts off +% recursive entries to save processing time. +% +% Revision 1.17.0.5 1997/11/01 11:38:52 root +% Fixed obvious error in initialization routine before testing; +% if the pinpoint date is greater than the beginning of the +% subrange, we just use that as the starting point. +% +% Revision 1.17.0.4 1997/11/01 11:34:41 root +% First draft of new "every other week" function. "Other" +% invokes a terminating macro that expects a pinpoint date. +% This is then used as the base for every-other-week jumps. +% +% Revision 1.17.0.3 1997/11/01 11:13:35 root +% Moved setting of \dates@date in recursive entries from the +% generic opener \dates@read@exit@recurse into each of the +% alternative recursive definitions. This gives us better +% control; it allows us to use a pinpoint date as a starting date +% for recursive processing. +% +% Revision 1.17.0.2 1997/11/01 10:52:56 root +% Incorporated fix for encounters with \end; we no longer +% need to gobble anything after the parsed text. +% +% Revision 1.17.0.1 1997/11/01 06:39:29 root +% Cut enditalls. +% +% Revision 1.17 1997/11/01 06:29:27 root +% New revision branch established to play with the elimination +% of \enditall's from the code. +% +% Revision 1.16 1997/10/31 21:28:07 root +% *** empty log message *** +% +% Revision 1.15 1997/10/31 21:13:53 root +% *** empty log message *** +% +% Revision 1.14 1997/10/31 20:47:16 root +% Moved date-validation code from \dates@fix to +% \dates@read@exit@default where it belongs. +% +% Revision 1.13 1997/10/31 19:35:20 root +% Eliminated \message's used to trace the problem with the +% streamlined date conversion code just introduced. +% +% Revision 1.12 1997/10/31 19:32:42 root +% Fixed egregious bug involving the use of \dates@day for two +% completely unrelated purposes. With this fix, the more +% streamlined use of but one invocation of either \caldate or +% \dates@fix works. +% +% Revision 1.11 1997/10/31 18:51:19 root +% *** empty log message *** +% +% Revision 1.10 1997/10/31 18:29:43 root +% Eliminated what appeared to be unnecessary use of +% \dates@monthnameget from previous revision. Caused an error, +% but this may not have been the source of that error. +% +% Revision 1.9 1997/10/31 18:23:06 root +% Added \dates@getmonthname and \dates@getdayname to the definition +% of \dates@fix. This eliminates the need for running \caldate +% after \dates@fix, and will further reduce the processing burden. +% +% Revision 1.8 1997/10/31 18:01:23 root +% Finalized changes eliminating one use of \dates@capsdown. +% Also made further changes to documentation, and added +% (or rather changed) the name of \dates@@@@read@function +% and the following macro to \dates@@@read... to help make +% things a little easier to follow. +% +% Revision 1.7 1997/10/31 17:39:05 root +% Restored use of @default prefix for \dates@read. Also +% trying the elimination of one instance of \dates@capsdown. +% If this works, it will eliminate a great deal of clutter +% in save space. +% +% Revision 1.6 1997/10/31 11:18:55 root +% Further documentation updates and what I thought were trivial +% changes to the code. The trivial changes seem, however, to +% have broken the "list" declaration. +% +% Revision 1.5 1997/10/31 09:00:27 root +% First phase of combing through documentation. +% +% Revision 1.4 1997/10/29 20:08:04 bennett +% *** empty log message *** +% +% Revision 1.3 1997/10/29 13:50:13 root +% Restored use of date checking, after discovering that it +% works correctly if files are extracted using the -kv +% option. +% +% Revision 1.2 1997/10/29 11:47:37 root +% Eliminated optional date specification from RequirePackage{overword} +% +% Revision 1.1 1997/10/29 08:17:52 root +% Initial revision +% +%\fi +% +% \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} +% +% \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 +% +% \setcounter{StandardModuleDepth}{1} +% \DeleteShortVerb{\|} +% \MakeShortVerb{\"} +% +% \begin{abstract} +% \noindent This package provides macros for the parsing of dates +% using \LaTeXe{}. +% \end{abstract} +% +% \CheckSum{1916} +% +% \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). +% +% For a description of the syntax understood by +% the parser, and examples of how it can be +% extended, please see the Calendar package and +% the documentation for its associated style +% files. The documentation here is not intended +% for end users; it is provided for reference by +% style designers who might wish to use +% the parser in their own packages. +% +% \section{Calling the Parser} +% +% Printing of +% variable text (such as the text of the date) is +% done by passing that information through to 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. If you need to do this, you're +% on your own; please have a look at the code. +% +% 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 confirm the existence +% of the file, then run "\inputandread". +% +% \section{Extending the Parser} +% +% \label{analyze} +% 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. +% +% \subsection{Using the Argument Text} +% +% When dates are read they are unsorted, so text should not +% be exported directly by \cs{dates@action} (let alone +% dropped on DVI) +% unless you have a filter for sorting +% the text after \TeX{} exits. In normal use, +% events should be sorted and selected +% in memory after they are read, by other code in the +% package calling "dates.sty". The Calendar package +% is an example of how this can be done. +% +%\StopEventually{\PrintIndex} +% +% \section{The Macros} +% +% \begin{macrocode} +%<*style> +\newcount\dates@one +\newcount\dates@two +\newcount\dates@langnum +\newtoks\dates@reg@a +\newtoks\dates@reg@b +\newtoks\dates@reg@c +\def\DeclareCalendarLanguage#1#2#3#4#5{ + \advance\dates@two by1\relax% + \expandafter\edef\csname dates@#1@langnum\endcsname{\the\dates@two}% + \ifnum\dates@two=1\relax\def\dates@default@language{#1}\fi% + \DeclareOption{#1}{% + \expandafter\expandafter\expandafter% + \dates@langnum\csname dates@#1@langnum\endcsname\relax% + \dates@buildcase{1}{\theweekday}{\dates@weekd}#2{}% + \dates@buildcase{1}{\theshortweekday}{\dates@weekd}#3{}% + \dates@buildcase{0}{\themonth}{\dates@month}#4{}% + \dates@buildcase{0}{\theshortmonth}{\dates@month}#5{}}} +\def\dates@buildcase#1#2#3{% + \dates@one=#1\relax% + \dates@reg@c={#3}% + \gdef\dates@temp@a{#2}% + \dates@reg@a={}% + \dates@reg@b={}% + \def\dates@temp@c{}% + \dates@@buildcase} +\def\dates@@buildcase#1{% + \ifcat$#1$% + \let\next\dates@@@buildcase% + \else% + \let\next\dates@@buildcase% + \dates@reg@a={\or#1}% + \dates@reg@b=\expandafter{\dates@temp@c}% + \edef\dates@temp@c{\the\dates@reg@b\the\dates@reg@a} + \fi% + \next} +\def\dates@@@buildcase{% + \ifnum\dates@one=0\relax% + \dates@reg@a=\expandafter{\dates@temp@c}% + \else% + \dates@reg@a=\expandafter\expandafter\expandafter% + {\expandafter\@gobble\dates@temp@c}% + \fi% + \expandafter\edef\dates@temp@a{% + \noexpand\ifcase\the\dates@reg@c% + \the\dates@reg@a% + \noexpand\fi}} +% \end{macrocode} +% Load some useful code. +% \begin{macrocode} +\RequirePackage{overword}[1997/10/29] +\InputIfFileExists{dates.cfg}{}{} +\@ifundefined{theweekday}{% + \DeclareCalendarLanguage{english} + {{Sun}{Mon}{Tue}{Wed}{Thu}{Fri}{Sat}} + {{Sunday}{Monday}{Tuesday}{Wednesday}{Thursday}{Friday}{Saturday}} + {{Jan}{Feb}{Mar}{Apr}{May}{Jun}{Jul}{Aug}{Sep}{Oct}{Nov}{Dec}} + {{January}{February}{March}{April}{May}{June}{July}{August}{September} + {October}{November}{December}}} + {} +\ExecuteOptions{\dates@default@language} +\ProcessOptions +% \end{macrocode} +% +% \subsection{The Engine Core} +% +% \begin{macro}{\dateread} +% The top-level interface macro \cs{dateread} starts by setting "\dates@action" +% to be its first argument. It then initializes +% variables that are zeroed only at the start of a run +% of dates, and passes control to the next macro in the chain, +% \cs{dates@read}. +% \begin{macrocode} +\long\gdef\dateread#1{% + \gdef\dates@action{#1}% + \gdef\dates@subranges{}% + \dates@subrange@start=0% + \dates@subrange@end=0% + \dates@read@default} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\date@read} +% The next macro continues with initialization, +% zeroing and blanking variables that need to +% be reset each time a new date is read. The reason +% for the \texttt{@default} extension is explained below. +% \begin{macrocode} +\long\gdef\dates@read@default{% + \global\dates@time@start=0% + \global\dates@time@end=0% + \setyear{1900}% + \global\dates@month=0% + \global\dates@day=0% + \global\dates@weekd@target=7% + \gdef\theshorttext{}% + \gdef\thelongtext{}% +% \end{macrocode} +% \textit{The action, whatever the user has chosen it to be, +% can be suppressed by toggling the following condition, +% but the default here (as in life) is to do things.} +% \begin{macrocode} + \global\dates@suppressfalse% +% \end{macrocode} +% \textit{Recursive entries will define the following two macros, +% but initially we want them to be firmly turned off.} +% \begin{macrocode} + \global\let\dates@init\relax% + \global\let\dates@increment\relax% +% \end{macrocode} +% \textit{The following assignments put the parsing machinery +% into its default state. The first and the third macros below +% have \texttt{@default} values not to allow modification of +% parsing behaviour at these points, but because these two +% macros are \cs{relax}ed to bring parsing to a halt when +% desired.} +% \begin{macrocode} + \global\let\dates@read=\dates@read@default% + \global\let\dates@@@read=\dates@@@read@default% + \global\let\dates@@@@read=\dates@@@@read@default% + \global\let\dates@read@exit=\dates@read@exit@default% +% \end{macrocode} +% \textit{We open a group, and make uppercase characters active +% locally inside it. We use an invocation of \cs{@ifnextnparchar} +% to look for the next character. If that is \cs{end}, +% then we close the group we've just opened, and that's +% that. This sudden-death condition will seldom be satisfied +% (you would need an \cs{end} immediately after \cs{dateread} +% with no intervening date, or a date complete with braced +% argument(s) followed immediately by \cs{end}), but the condition will +% be trapped and handled if it does occur.} +% +% \textit{Apart from this, we look for a match to \cs{dates@serious@brace}. +% It will be spotted in most cases +% by the last invocation of \cs{@ifoverword} in parsing the +% date (re which see below). The only case in which it will +% need to be caught here is where there is no date at all, +% but an immediate curly brace.} +% +% \textit{Thus, we will almost always be proceeding +% on the middle, ``fail'' condition to the next macro in +% the parsing chain, \cs{dates@@read}.} +% +% \textit{Apart from +% handling possible if slightly weird error conditions, this +% look forward will close a file, if one has been opened +% to provide the list read by \cs{dateread} (see \texttt{calendar.dtx}, +% again, for a real-world example) and its text content has +% been exhausted.} +% \begin{macrocode} + \bgroup% + \@ifnextnparchar\dates@serious@brace% + {\message{This should never happen}}% + {\dates@@read}% + {\egroup}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\date@@read} +% We grab everything up to the next brace. This +% will ordinarily be a single date, but it could be a +% range as well. The text for parsing is \cs{xdef}ed, +% after first \cs{let}ting \cs{end} \cs{relax}. +% The \cs{relax}ed \cs{end} will expand to itself +% (I think they call this a ``quark''?) when \cs{xdef}ed. +% Then we end the current group, which +% will restore the definition +% of \cs{end}, whatever it may happen to be. +% +% We then place a space after the argument text to be +% sure we have one there, and +% run the next macro, \cs{dates@@@read}, in front of +% it. +% \begin{macrocode} +\long\def\dates@@read#1#{% + \let\end\relax% + \xdef\cal@temp{#1 }% + \egroup% + \expandafter\dates@@@read\cal@temp} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\date@@@read} +% The \cs{dates@@@read@default} macro recursively +% picks through the argument text word by word +% using the \cs{@ifoverword} macro provided by the +% \texttt{overword} package. Through the subsequent macro +% "\dates@analyze", the definitions of +% "\dates@@@read" and of "\dates@read@exit" +% may be altered to achieve special effects. Any hooks that +% redefine these functions should chain to +% their default definitions. +% +% The \cs{@ifoverword} macro looks for \cs{dates@serious@brace} +% that we just placed after the scanned date string +% between us and the curly brace. +% +% This is one +% of several macros in the parsing chain that can +% be replaced with an alternative definition to +% accomplish special effects. +% In this code, the default +% definitions of such macros bear the root name with +% suffix "@default". Special definitions bear the root name +% with a descriptive suffix. +% \begin{macrocode} +\def\dates@@@read@default{% +% \end{macrocode} +% \textit{If this macro has been called, we carefully be +% sure it's set as the default under the root name too.} +% \begin{macrocode} + \global\let\dates@@@read\dates@@@read@default% + \@ifoverword\dates@serious@brace% +% \end{macrocode} +% \textit{If there is a match, we're at the end of the +% string. We send the word we've collected to \cs{dates@analyze}, +% and chain to the next +% processing macro, \cs{dates@@@@read}, when it exits.} +% \begin{macrocode} + {\expandafter\dates@analyze\@overword{}% + \dates@@@@read}% +% \end{macrocode} +% \textit{If the next token after the word we have just absorbed +% is not a brace (and not \cs{end}), then we send the +% absorbed word to \cs{dates@analyze} and reinvoke the +% current macro.} +% \begin{macrocode} + {\expandafter\dates@analyze\@overword{}% + \dates@@@read}% +% \end{macrocode} +% \textit{If we have hit \cs{end}, we want to recover gracefully, +% completing our work before expiring so that the \cs{end} +% can take effect.} +% +% \textit{The first thing we do is send the absorbed word to +% \cs{dates@analyze}. Then we invoke \cs{dates@read@exit} to +% process the date (calculating the long date, and performing +% the action specified in the argument to \cs{dateread}) --- +% after first relaxing \cs{dates@read}, so that the +% \cs{dates@read@exit} macro will occur only once.} +% \begin{macrocode} + {\expandafter\dates@analyze\@overword{}% + \ifnum\dates@year>0\relax% + \let\dates@read\relax% + \dates@read@exit% + \fi}} +% \end{macrocode} +% \end{macro} +% \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". +% +% The macro is defined with a \texttt{@default} suffix, +% not because alternative processing is to be spliced in here, +% but because one method of ending recursive parsing +% is to \cs{let} this macro \cs{relax}. +% +% The effect we want to accomplish is to allow +% users to put any legal text, including square +% braces, inside \textrm{either} the curly braces marking +% the mandatory argument, \textrm{or} the square braces +% marking the optional argument. The usual \LaTeX{} method +% of doing this, looking for a common or garden square brace +% with \cs{@ifnextchar} and then chaining to a +% macro that uses square braces as delimiters, +% will not accomplish this purpose; with that approach, +% \textrm{any} square brace, regardless of nesting level, +% will end the argument. +% +% We need instead to see square braces as grouping characters. +% This will make them disappear when the text is expanded, but +% at least things won't blow up. +% +% To get ready for the optional argument (which comes \textrm{after} +% this macro), we set the open square brace to be a grouping +% character like "{". We can't use this directly as an argument +% (because \TeX{} will try to keep reading +% text until it finds the matching brace), so we \cs{let} +% a macro have this token's value. The \cs{let} is +% global because the value of "{" is global. +% Then we use the funny brace macro inside the +% definition as a match text for a square brace. This +% works because the \cs{@ifnextnparchar} macro also works +% with \cs{let} (well, \cs{futurelet}, which amounts to the +% same thing in this context), resulting in an internal +% ``funny brace'' macro used for the comparison. +% All of this jiggery-pokery is necessary because +% the "\futurelet" command (used by "\@ifnextnparchar") will stamp +% a category code on the brace when it sees it, even though +% \TeX{} won't yet read the character itself in for processing. +% \begin{macrocode} +\bgroup + \catcode`\[=1 + \global\let\dates@funny@brace=[ + \catcode`\<=1 + \global\let\dates@bent@brace=< +\egroup +\gdef\dates@@@@read@default#1{% +% \end{macrocode} +% We reset any alternative definitions that are accidentally +% in force, and save the text of the mandatory argument +% to its macro for future reference. +% \begin{macrocode} + \global\let\dates@@@@read\dates@@@@read@default% + \global\let\dates@@@read\dates@@@read@default% + \dates@textcount1% + \def\theshorttext{#1}% + \ifnum\dates@textcount=\dates@langnum\relax% + \gdef\thelongtext{}% + \fi% +% \end{macrocode} +% Here is where the funny brace macro referred to above +% comes into play. We change the catcodes so that +% square-brace-enclosed text will be interpreted as +% a single argument. Then we look for a brace. If +% a brace is found, we invoke \cs{dates@@@@@read} +% to read and store the text. If not, we cut off the +% special category code for square braces and +% call the macro that interprets dates (since we already +% know that we've finished with a date, and have grabbed +% the mandatory text. Likewise, if we see an \cs{end} +% out there (i.e. there was a curly-brace-enclosed +% mandatory argument right after the date, but it's +% followed immediately by \cs{end}), we also process +% the digested date before proceeding. Note that the +% \cs{end} in this event will be caught by the lookahead +% machinery at the top of the parsing chain the next time +% around, causing macro recursion to terminate. +% \begin{macrocode} + \bgroup% + \catcode`\[=1\catcode`\]=2\relax% + \catcode`\<=1\catcode`\>=2\relax% + \@ifnextnparchar\dates@funny@brace% + {\dates@@@@@read}% + {\global\let\thelongtext\theshorttext% + \@ifnextnparchar\dates@bent@brace% + {\dates@@@@read@bent}% + {\egroup% + \dates@read@exit}% + {\message{This can't happen}}}% + {\egroup% + \dates@read@exit}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\dates@@@@@read} +% 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 by an \cs{egroup} here. +% Apart from that, we just grab the text to a macro, +% and call the macro that does the final processing +% of the date and text information. +% \begin{macrocode} +\def\dates@@@@@read#1{% + \egroup% + \ifnum\dates@textcount=1\relax + \gdef\thelongtext{#1}% + \else% + \ifnum\dates@textcount=\dates@langnum\relax% + \gdef\thelongtext{#1}% + \fi% + \fi% + \bgroup% + \catcode`\<=1\catcode`\>=2\relax% + \@ifnextnparchar\dates@bent@brace% + {\dates@@@@read@bent}% + {\egroup% + \dates@read@exit}% + {\egroup% + \dates@read@exit}} +% \end{macrocode} +% \end{macro} +% \begin{macrocode} +\def\dates@@@@read@bent#1{% + \egroup% + \advance\dates@textcount by1\relax% + \ifnum\dates@textcount=\dates@langnum\relax + \def\theshorttext{#1}% + \fi% + \bgroup% + \catcode`\[=1\catcode`\]=2\relax% + \catcode`\<=1\catcode`\>=2\relax% + \@ifnextnparchar\dates@funny@brace% + {\dates@@@@@read}% + {\ifnum\dates@textcount=\dates@langnum\relax% + \gdef\thelongtext{}% + \fi% + \@ifnextnparchar\dates@bent@brace% + {\dates@@@@read@bent}% + {\egroup% + \dates@read@exit}% + {\message{This can't happen}}}% + {\egroup% + \dates@read@exit}} +% \end{macrocode} +% \begin{macro}{\dates@read@exit} +% +% \begin{macrocode} +\def\dates@read@exit@default{% + \dates@verify% + \dates@fix% + \dates@lastdate\dates@date% + \ifdates@suppress@global% + \else% + \ifdates@suppress% + \else% + \dates@action% + \fi% + \fi% + \dates@read} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\dates@verify} +% This macro is used in a few places to verify whether +% all of the necessary date information is present. +% It uses a couple of toggles to allow different bits +% of the address to be confirmed. +% \begin{macrocode} +\def\dates@verify{% + \ifnum\dates@month=0% + \ifdates@requiremonth% + \PackageError{dates}{Missing month.}{}% + \else% + \global\dates@month=1% + \fi% + \fi% + \ifnum\dates@day=0% + \ifdates@requireday% + \PackageError{dates}{Missing day of the month.}{}% + \else% + \global\dates@day=1% + \fi% + \fi% + \ifnum\dates@year=0\relax% + \PackageError{dates}{Missing year in ordinary date.}{}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \subsection{Selective Handling} +% +% There are three points at which special handling can +% be spliced into the parsing routine. The defaults of +% these macros have all been presented above. Below, +% alternative versions internal to the \texttt{dates} +% package itself are set forth. +% +% The following is the default value of "\dates@read@exit". +% It fixes the date, rationalizes the registers +% containing human-readable date information, and +% saves the date for future reference (i.e.~in case +% we need it as the beginning of a range). +% It then performs the action given by the user in the +% argument to "\dateread", and attempts to chain back to continue +% parsing within the presented list of dates. +% +% \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% + \dates@subrange@end\dates@date% + \dates@reg@a=\expandafter{\dates@subranges}% + \xdef\dates@subranges{% + \the\dates@reg@a% + \noexpand\delim{\the\dates@subrange@start}% + {\the\dates@date}}% + \global\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% + \ifnum\dates@month>0\relax% + \dates@everyyear@month\dates@month% + \global\let\dates@init\dates@init@yearly@doy% + \global\let\dates@increment\dates@increment@yearly@doy% + \else% + \global\let\dates@init\dates@init@monthly@dom% + \global\let\dates@increment\dates@increment@monthly@dom% + \fi% + \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% + \global\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% +% \ifnum\dates@subrange@end>\dates@range@limit% +% \dates@subrange@end\dates@range@limit% +% \fi% + \dates@init% + \caldate% + \ifdates@suppress@global% + \else% + \ifdates@suppress% + \else% + \dates@action% + \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% + \let\next\relax% + \else% + \caldate% + \ifdates@suppress@global% + \else% + \ifdates@suppress% + \else% + \dates@action% + \fi% + \fi% + \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{% + \global\dates@date\dates@subrange@start% + \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} +\def\dates@init@semiweekly{% + \dates@verify% + \dates@fix% + \ifnum\dates@subrange@start>\dates@date% + \dates@ct@z\dates@subrange@start% + \advance\dates@ct@z by-\dates@date% + \mod{14}\dates@ct@z\dates@catch% + \global\dates@date\dates@subrange@start% + \global\advance\dates@date by\dates@catch% + \fi} +% \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} +\def\dates@increment@semiweekly{% + \global\advance\dates@date by14\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{% + \global\dates@date\dates@subrange@start% + \dates@init@monthly@@dow} +\def\dates@init@monthly@@dow{% + \let\dates@init@monthly@dow@recurse\relax% + \caldate% + \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{% + \global\dates@date\dates@subrange@start% + \dates@init@monthly@@dom} +\def\dates@init@monthly@@dom{% + \let\dates@init@monthly@dom@recurse\relax% + \caldate% + \ifnum\dates@day>\dates@everymonth@day% + \dates@next@month% + \let\dates@init@monthly@dom@recurse\dates\init@monthly@@dom% + \else% + \global\dates@day\dates@everymonth@day% + \dates@fix% + \fi% + \dates@init@monthly@dom@recurse} +\def\dates@init@yearly@doy{% + \global\dates@date\dates@subrange@start% + \dates@init@yearly@@doy} +\def\dates@init@yearly@@doy{% + \let\dates@init@yearly@doy@recurse\relax% + \caldate% + \dates@ct@z\dates@day@offset% + \global\dates@day\dates@everymonth@day% + \global\dates@month\dates@everyyear@month% + \dates@fix% + \ifnum\dates@ct@z>\dates@day@offset% + \nextyear% + \dates@fix% + \let\dates@init@yearly@doy@recurse\dates@init@yearly@@doy% + \fi% + \dates@init@yearly@doy@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} +\def\dates@increment@yearly@doy{% + \nextyear% + \global\dates@month=\dates@everyyear@month\relax% + \global\dates@day=\dates@everymonth@day\relax% + \dates@fix% + \dates@init@yearly@@doy} +% \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 {% + \xdef\dates@init{\csname#1\endcsname}% + \xdef\dates@increment{\csname#2\endcsname}% + \@ifnextnparchar\dates@serious@brace% + {\bgroup% + \makeatletter% + \expandafter\dates@@@read@@function}% + {\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 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% + \global\multiply\dates@time@start by 60% + \global\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% + \global\dates@time@start=\dates@arg@a\relax% + \global\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% + \global\dates@time@end=\dates@arg@a\relax% + \global\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)] 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% + \global\dates@catch=`#1\relax + \global\advance\dates@catch by-65 + \dates@reg@a=\expandafter{\ifcase\dates@catch + a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or + m\or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or + y\or z\else #1\fi} + \csname\the\dates@reg@a#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, hacked +% together by Frank Bennett in January 1997, but awaited +% final testing while the Timetable package stabilized. +% It was reported to fail by Miroslav on 5 March 1997, +% and a fix was put in place and released by Frank on 6 March. +% +% \begin{macrocode} +\def\daymac{% + \global\let\dates@init=\dates@init@daily% + \global\let\dates@increment=\dates@increment@daily} +\def\dates@init@daily{% + \global\dates@date=\dates@subrange@start} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\othmac} +% +% "Other" will modify the effect of "every" to +% choose every other date within the range, beginning +% with the specified date. The specified date need not +% be within the range. +% \begin{macrocode} +\def\othmac{% + \global\let\dates@init=\dates@init@semiweekly% + \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}{\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% + \global\dates@month=0% + \global\dates@day=0% + \setyear{1900}% + \fi% + \global\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@init\relax% + \global\let\dates@init\dates@init@weekly% + \fi% + \ifx\dates@increment\relax% + \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} +%<*cull> +\bgroup +\dates@reg@a={} +\gdef\dates@capsdown{} +\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}% + \let\next\dates@capsactive% + \next} +\dates@capsactive% + AAaBBbCCcDDdEEeFFfGGgHHhIIiJJjKKk% + LLlMMmNNnOOoPPpQQqRRrSSsTTtUUuVVv% + WWwXXxYYyZZz\end +\egroup +%</cull> +% \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{% + \global\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% + \global\dates@month=1% + \global\dates@day=1% + \else% + \global\advance\dates@month by 1% + \global\dates@day=1% + \fi% + \dates@fix} +% \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{% + \global\dates@yearbase=-1% + {\dates@ct@z=\dates@year\divide\dates@ct@z by4% + \multiply\dates@ct@z by4\relax% + \ifnum\dates@year=\dates@ct@z% + \global\dates@catch=0% + \else% + \global\dates@catch=1% + \fi}% + \ifcase\dates@catch \leapyeartrue\or% + \leapyearfalse\fi% + {\dates@ct@z=\dates@year\multiply\dates@ct@z% + by1461\advance\dates@ct@z by3% + \divide\dates@ct@z by4% + \global\dates@catch=\dates@ct@z}% + \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}% +% ??????????? ************ global okay here? + \global\dates@day@offset=\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. +% +% This can now be invoked by itself; there is no need to follow +% it with \cs{caldate}. +% \begin{macrocode} +\def\dates@fix{% + \dates@year@get% + \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% + \global\dates@date=\dates@day{\advance\dates@month by-1% + \monthdays% + \global\advance\dates@date by\dates@day@offset% + \global\advance\dates@date by\dates@yearbase}% + \fi% + \dates@dayname@get} +% \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", +% the mod in "#3". +% +% \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{% + \global\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} +% \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\global\dates@month=0% + \loop\monthdays\ifnum\dates@day@offset<\dates@date% + \global\advance\dates@month by1\repeat% + {\advance\dates@month by-1\monthdays% + \advance\dates@date by-\dates@day@offset% + \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". The definition here +% is performed in the alternative, depending upon +% the value of the "\dates@language" counter. This +% counter is set in the options section. Packages +% which draw on the Dates package (such as Calendar, +% and the various Calendar style packages) can pass +% the language options down to the Dates package through +% the standard \LaTeXe{} package interface. Because Japanese +% high-bit code may case a non-Japanese version of +% \LaTeXe to fail, we allow for its exclusion here. +% The odd structure of this is necessary to cope with the +% fact that the "\ifcase" function is blind to the nesting +% of case conditions. +% \begin{macrocode} +% Japanese removed. +\def\dates@monthname@get{% + \ifcase\dates@month% + \or% + \global\dates@days=31\relax% + \or% + \ifleapyear% + \global\dates@days=29\relax% + \else% + \global\dates@days=28\relax% + \fi% + \or% + \global\dates@days=31\relax% + \or% + \global\dates@days=30\relax% + \or% + \global\dates@days=31\relax% + \or% + \global\dates@days=30\relax% + \or% + \global\dates@days=31\relax% + \or% + \global\dates@days=31\relax% + \or% + \global\dates@days=30\relax% + \or% + \global\dates@days=31\relax% + \or% + \global\dates@days=30\relax% + \or% + \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{{\dates@ct@z=#1\mod7\dates@date\dates@weekd% + \advance\dates@ct@z by-\dates@weekd\relax% + \ifnum\dates@ct@z<0\advance\dates@ct@z by7\fi% + \global\advance\dates@date by\dates@ct@z}} +% \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% +%\message{Ran jdttol^^J}% + \advance\dates@date by\dates@timezone% + \global\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 = dates@ct@z*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\dates@ct@z% + \multiply\count2 by\dates@ct@z\relax% + \multiply\count3 by\dates@ct@z% + \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} +% +% Before anything further is executed, the following registers +% and macros need to be in place. +% +% \begin{macrocode} +\newcount\dates@textcount +\newcount\dates@ct@z +\newcount\dates@range@limit +\newcount\dates@year +\newcount\dates@timezone +\dates@timezone=0 +\newcount\dates@catch +\newcount\dates@day +\newcount\dates@day@offset +\newcount\dates@everymonth@day +\newcount\dates@everyyear@month +\newcount\dates@month +\newcount\dates@date +\newcount\dates@date@current +\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\ifdates@requiremonth +\newif\ifdates@requireday +\newif\ifdates@suppress +\newif\ifdates@suppress@global +\newif\ifleapyear +\let\delim\relax +\let\dates@serious@brace={ +\def\dates@empty{} +%</style> +% \end{macrocode} +% +%\iffalse +% +% \section{Demonstration File} +% +% \begin{macrocode} +%<*demo> +\documentclass{minimal} +\usepackage{dates} +\begin{document} + +\makeatletter +% +% We say HI to the user +\message{^^J---------------------------------------------------------} +\message{This is a demonstration file for the LaTeX dates package.} +\message{It will print a number of dates to the terminal.^^J} +\message{The code demonstrated by this package is not intended} +\message{for direct use by humans, so I have not worked very hard} +\message{to make its output look pretty, and it won't actually} +\message{print anything. But if you get a cluttered list of dates} +\message{and no error messages, the package is working for you.} +\message{---------------------------------------------------------} +% +% We invoke the \dateread command. +% +\dateread +% +% We tell it to report a few details to the terminal. +% +{\message{\theshorttext}% + \message{\theday/\the\dates@month/\the\dates@year}% + \ifx\thelongtext\dates@empty% + \else% + \message{\thelongtext}% + \fi} +% +% The following are ranges. +% + december 10 1995 {Start of First Period of Time} +to jan 10 1996 {End of First Period of Time} + december 10 1996 {Start of Second Period of Time} +to jan 10 1997 {End of Second Period of Time} +% +% The following are specific dates (obviously) +% +February 18 1997 {Frank'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 {Frank's Next Birthday But One} +% +% These are a couple of recursive dates. +% +Every Monday {(Monday Coffee)} +Every Third Tuesday {(Third Tuesday Meeting)} +Function moonsinit moonsincrement {% + \global\dates@date=\dates@subrange@start% + \caldate% + \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} +% Compute date for cycle quarter MOONNO + \def\moondate{{\dates@ct@z=\moonno + \lin 202.126.369+0.\dates@ct@z=\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} +% 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 } +% 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 } +% Events for phases. +% Uses PHASE (local). + \def\phase{{\dates@ct@z=\moonno + \count1=\moonno + \divide\dates@ct@z by4\multiply\dates@ct@z by4 + \advance\count1 by-\dates@ct@z\relax + \xdef\themoon{\ifcase\count1 + New Moon\or First Quarter\or + Full Moon\or Last Quarter\fi}}} + \gdef\moonsinit{% + \firstmoon + \global\dates@month=12\global\dates@day=31\dates@fix\global\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} +% \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}} + } + +\generate{\file{demodate.tex} {\from{dates.dtx}{demo}} + } + +\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 + |