remind-03.01.15/COPYRIGHT0000644000076400007640000003634712514120337012647 0ustar dfsdfsTHE REMIND COPYRIGHT 1. REMIND refers to the entire set of files and documentation in the REMIND package. 2. REMIND is Copyright 1999-2010 Roaring Penguin Software Inc., except where noted in individual files. 3. DISTRIBUTION AND USE REMIND may be used and distributed according to the terms of the GNU General Public License, Version 2, which follows: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS -- Dianne Skoll Tel. (613) 231-6599 http://www.roaringpenguin.com remind-03.01.15/MICROSOFT-AND-APPLE0000644000076400007640000000220712514120337014067 0ustar dfsdfsMICROSOFT WINDOWS ================= I used to prohibit porting Remind to Microsoft Windows. However, this may cause problems with the GPL, so I have removed that restriction. Although I cannot prevent you from porting Remind to Windows, I appeal to you not to do it. I am trying to encourage the growth of free software, not proprietary software. If you port Remind to Windows, I will not provide support or answers to questions -- you're on your own. On the other hand, I will feel no guilt in taking enhancements and merging them into the UNIX stream. APPLE ===== I can't prevent you from using Remind on Apple's products, but I hope you don't. Apple's corporate culture is the very antithesis of Free Software. Rather than using Mac OS X, I encourage you to switch to Linux or FreeBSD, two Free Software operating systems that are every bit as capable as Mac OS X and which are unencumbered by Apple's arbitrary restrictions. And if you're looking to port Remind to other Apple products like the iPhone or iPad, please don't. Those products enforce Apple's rigorous controls much more stringently than Mac OS X on an Apple PC. -- Dianne Skoll remind-03.01.15/Makefile0000644000076400007640000000135011363632564013011 0ustar dfsdfs# Top-level Makefile for Remind. all: src/Makefile @echo "" @echo "*******************" @echo "* *" @echo "* Building REMIND *" @echo "* *" @echo "*******************" @echo "" @cd src; $(MAKE) all LANGDEF=$(LANGDEF) install: @echo "" @echo "*********************" @echo "* *" @echo "* Installing REMIND *" @echo "* *" @echo "*********************" @echo "" cd src; $(MAKE) install clean: find . -name '*~' -exec rm {} \; cd src; $(MAKE) clean test: @cd src && $(MAKE) test distclean: clean rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile src/Makefile: src/Makefile.in ./configure # DO NOT DELETE remind-03.01.15/README0000644000076400007640000000231711057403122012217 0ustar dfsdfs REMIND Remind is a full-featured calendar/alarm program. Copying policy is in the file "COPYRIGHT" in this directory. Installation notes for various operating systems are in "docs". See the appropriate README file for installation on your system. Manual pages are in "man". ----------------------------------------------------------------------------- Quick UNIX installation instructions for the very impatient: If you have Tcl/Tk (wish 4.1 or higher) installed and are running X Windows: -------------------------------------------------------------- 1) Type: wish ./build.tk from this directory. Fill in the various options and hit "Build Remind" 2) Type: "make install" -- you may need to be root to do this. If you do NOT have Tcl/Tk or are NOT running X Windows: ------------------------------------------------------- 1) Edit the file "src/custom.h" according to your preferences. 2) Edit the file "src/lang.h" to choose a language. 3) Type: "./configure" (You can supply options; type "./configure --help" for details.) 4) Type: "make" 5) Type: "make install" -- you may need to be root to do this. Contact info: mailto:dfs@roaringpenguin.com Home page: http://www.roaringpenguin.com/remind remind-03.01.15/build.tk0000644000076400007640000020714712514120337013011 0ustar dfsdfs#!/bin/sh # -*-Mode: TCL;-*- #-------------------------------------------------------------- # BUILD.TK # # A cheesy graphical front-end for building and installing REMIND. # # This file is part of REMIND. # Copyright (C) 1992-1999 Dianne Skoll # Copyright (C) 1999-2000 Roaring Penguin Software Inc. # #-------------------------------------------------------------- # the next line restarts using wish \ exec wish "$0" "$@" #*********************************************************************** # %PROCEDURE: SetConfigDefaults # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Sets up default values for various parameters. #*********************************************************************** proc SetConfigDefaults {} { global Config set Config(LAT_DEG) 45 set Config(LAT_MIN) 24 set Config(LON_DEG) 75 set Config(LON_MIN) 39 set Config(LOCATION) "Ottawa" set Config(DEFAULT_PAGE) "Letter" set Config(DATESEP) "-" set Config(TIMESEP) ":" set Config(ISOLATIN1) 0 set Config(IBMEXTENDED) 0 set Config(ISOLATIN2) 0 set Config(IBM852) 0 set Config(NORTHERN_HEMISPHERE) 1 set Config(WESTERN_HEMISPHERE) 1 set Config(LANGUAGE) "English" set Config(INST_DIR) "/usr/local/bin" set Config(MAN_DIR) "/usr/local/man" } #*********************************************************************** # %PROCEDURE: Bail # %ARGUMENTS: # msg -- a message # %RETURNS: # Does not return # %DESCRIPTION: # Pops up an error dialog; then calls exit. #*********************************************************************** proc Bail { msg } { tk_dialog .err "Remind Configuration Error" $msg error 0 "Bummer" exit 1 } #*********************************************************************** # %PROCEDURE: CheckSanity # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Checks sanity of install dir -- checks for critical files, # warns user if something looks wrong. #*********************************************************************** proc CheckSanity {} { if {![file executable ./configure]} { wm withdraw . Bail "I can't seem to execute the file ./configure -- make sure you have all required files and are running this from the top-level Remind directory" } if {![file readable ./src/custom.h.in]} { wm withdraw . Bail "I can't seem to find the file src/custom.h.in -- make sure you have all required files and are running this from the top-level Remind directory" } } #*********************************************************************** # %PROCEDURE: CreateMainDialog # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Creates and displays the main configuration dialog #*********************************************************************** proc CreateMainDialog {} { global Instdir Loc Options wm title . "Remind Configuration" wm iconname . "Remind Config" doLogo destroy .c update idletasks SetConfigFromRemind tabnotebook_create .tn set Instdir [tabnotebook_page .tn "Installation Directories"] CreateInstallDirDialog $Instdir set Loc [tabnotebook_page .tn "Location"] CreateLocationDialog $Loc set Options [tabnotebook_page .tn "Options"] CreateOptionsDialog $Options pack .tn -side top -expand 1 -fill both frame .buttons button .build -text "Build Remind" -command BuildRemind button .cancel -text "Cancel" -command exit pack .build .cancel -in .buttons -side left -expand 1 -fill both pack .buttons -side top -expand 0 -fill x } #*********************************************************************** # %PROCEDURE: CreateInstallDirDialog # %ARGUMENTS: # w -- frame containing widgets # %RETURNS: # Nothing # %DESCRIPTION: # Creates the "installation directories" dialog. #*********************************************************************** proc CreateInstallDirDialog { w } { global Config label $w.binlabel -text "Location for programs: " entry $w.bin -width 30 $w.bin insert end $Config(INST_DIR) label $w.manlabel -text "Location for man pages: " entry $w.man -width 30 $w.man insert end $Config(MAN_DIR) text $w.blurb -width 1 -height 5 -wrap word -relief flat -takefocus 0 $w.blurb insert end "\n(Tabbed-notebook Tcl code taken from \"Effective Tcl/Tk Programming\" by Mark Harrison and Michael McLennan, Addison-Wesley Professional Computing Series.)" $w.blurb configure -state disabled # Disable all text-window behaviour bindtags $w.blurb {NoSuchTag} grid $w.binlabel -row 0 -column 0 -sticky e grid $w.bin -row 0 -column 1 -sticky nsew grid $w.manlabel -row 1 -column 0 -sticky e grid $w.man -row 1 -column 1 -sticky nsew grid $w.blurb - -sticky nsew } #*********************************************************************** # %PROCEDURE: CreateLocationDialog # %ARGUMENTS: # w -- frame containing dialog # %RETURNS: # Nothing # %DESCRIPTION: # Creates the location dialog #*********************************************************************** proc CreateLocationDialog { w } { global Config scale $w.latdeg -label "Latitude (degrees)" -orient horizontal \ -from 0 -to 89 -length 300 -variable Config(LAT_DEG) scale $w.latmin -label "Latitude (minutes)" -orient horizontal \ -from 0 -to 59 -length 300 -variable Config(LAT_MIN) scale $w.londeg -label "Longitude (degrees)" -orient horizontal \ -from 0 -to 179 -length 300 -variable Config(LON_DEG) scale $w.lonmin -label "Longtude (minutes)" -orient horizontal \ -from 0 -to 59 -length 300 -variable Config(LON_MIN) radiobutton $w.north -text "Northern Hemisphere" \ -variable Config(NORTHERN_HEMISPHERE) -value 1 radiobutton $w.south -text "Southern Hemisphere" \ -variable Config(NORTHERN_HEMISPHERE) -value 0 radiobutton $w.west -text "Western Hemisphere" \ -variable Config(WESTERN_HEMISPHERE) -value 1 radiobutton $w.east -text "Eastern Hemisphere" \ -variable Config(WESTERN_HEMISPHERE) -value 0 label $w.loclab -text "City or Town: " entry $w.location -width 20 $w.location insert end $Config(LOCATION) grid $w.latdeg - grid $w.latmin - grid $w.londeg - grid $w.lonmin - grid $w.north $w.west grid $w.south $w.east grid $w.loclab -sticky e grid $w.location -sticky nsew -row 6 -column 1 } #*********************************************************************** # %PROCEDURE: CreateOptionsDialog # %ARGUMENTS: # w -- frame containing dialog # %RETURNS: # Nothing # %DESCRIPTION: # Creates the options dialog #*********************************************************************** proc CreateOptionsDialog { w } { global Config label $w.pagelabel -text "Default page size: " menubutton $w.page -text $Config(DEFAULT_PAGE) \ -indicatoron 1 -relief raised \ -menu $w.page.menu menu $w.page.menu -tearoff 0 $w.page.menu add command -label "Letter" \ -command "$w.page configure -text Letter" $w.page.menu add command -label "A4" -command "$w.page configure -text A4" grid configure $w.pagelabel -row 0 -column 0 -sticky e grid configure $w.page -row 0 -column 1 -sticky nsew label $w.datelabel -text "Default date separator: " menubutton $w.date -text $Config(DATESEP) -indicatoron 1 -relief raised \ -menu $w.date.menu menu $w.date.menu -tearoff 0 $w.date.menu add command -label "/" -command "$w.date configure -text /" $w.date.menu add command -label "-" -command "$w.date configure -text -" grid configure $w.datelabel -row 1 -column 0 -sticky e grid configure $w.date -row 1 -column 1 -sticky nsew label $w.timelabel -text "Default time separator: " menubutton $w.time -text $Config(TIMESEP) -indicatoron 1 -relief raised \ -menu $w.time.menu menu $w.time.menu -tearoff 0 $w.time.menu add command -label ":" -command "$w.time configure -text :" $w.time.menu add command -label "." -command "$w.time configure -text ." grid configure $w.timelabel -row 2 -column 0 -sticky e grid configure $w.time -row 2 -column 1 -sticky nsew label $w.charlabel -text "Character set: " menubutton $w.char -text "ISO 8859-1" -indicatoron 1 -relief raised \ -menu $w.char.menu menu $w.char.menu -tearoff 0 $w.char.menu add command -label "ISO 8859-1" -command "$w.char configure -text {ISO 8859-1}" $w.char.menu add command -label "ISO 8859-2" -command "$w.char configure -text {ISO 8859-2}" $w.char.menu add command -label "IBM Extended" -command "$w.char configure -text {IBM Extended}" $w.char.menu add command -label "IBM CPI-852" -command "$w.char configure -text {ISO 8859-2}" $w.char.menu add command -label "Plain ASCII" -command "$w.char configure -text {Plain ASCII}" grid configure $w.charlabel -row 3 -column 0 -sticky e grid configure $w.char -row 3 -column 1 -sticky nsew label $w.langlabel -text "Language: " menubutton $w.lang -text $Config(LANGUAGE) -indicatoron 1 -relief raised \ -menu $w.lang.menu menu $w.lang.menu -tearoff 0 foreach lang { "Brazilian Portuguese" "Danish" "Dutch" "English" "Finnish" "French" "German" "Italian" "Norwegian" "Polish" "Romanian" "Spanish" "Icelandic" } { $w.lang.menu add command -label $lang -command [list $w.lang configure -text $lang] } grid configure $w.langlabel -row 4 -column 0 -sticky e grid configure $w.lang -row 4 -column 1 -sticky nsew } #*********************************************************************** # %PROCEDURE: BuildRemind # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Builds Remind by: # -- creating custom.h from custom.h.in # -- running ./configure # -- running make #*********************************************************************** proc BuildRemind {} { pack forget .tn pack forget .buttons wm title . "Remind Configuration Status" text .msgs -width 130 -height 35 -wrap char -yscrollcommand ".sb set" scrollbar .sb -orient vertical -command ".msgs yview" .msgs tag configure green -foreground #005500 .msgs tag configure red -foreground #990000 pack .msgs -side left -expand 1 -fill both pack .sb -side left -expand 0 -fill y update .msgs insert end "\n>>> Creating src/custom.h...\n\n" green CreateCustomH .msgs insert end ">>> Calling `./configure'...\n\n" green CallConfigure .msgs insert end ">>> Calling `make'...\n\n" green CallMake .msgs insert end "\n----------------------------------------------\n\n" .msgs insert end "Remind" red .msgs insert end " has been built. To install it, type:\n\n" .msgs insert end "make install\n\n" green .msgs insert end "from the top-level " .msgs insert end "Remind" red .msgs insert end " directory. (You may need to be root.)\n\n" .msgs insert end "After it's installed, create an empty file called:\n" .msgs insert end " \$HOME/.reminders\n" green .msgs insert end "and type " .msgs insert end "tkremind" green .msgs insert end " for a nice easy introduction to " .msgs insert end "Remind.\n\n" red .msgs insert end "Press me to exit --> " button .msgs.ok -text "OK" -command "exit" .msgs window create end -window .msgs.ok .msgs see end } #*********************************************************************** # %PROCEDURE: RunCommand # %ARGUMENTS: # cmd -- shell command to run # %RETURNS: # Return code of command # %DESCRIPTION: # Runs a command putting output into ".msgs" #*********************************************************************** proc RunCommand { cmd } { global CmdDone set CmdDone 0 .msgs insert end "$cmd\n" red set problem [catch {set CmdFile [open "|$cmd" "r"]} err] if {$problem} { Bail "Error running command `$cmd': $err" } fconfigure $CmdFile -blocking 0 fileevent $CmdFile readable "CommandReadable $CmdFile" vwait CmdDone set problem [catch {close $CmdFile} err] if {$problem} { Bail "Error running command `$cmd': $err" } } #*********************************************************************** # %PROCEDURE: CommandReadable # %ARGUMENTS: # f -- file to read from # %RETURNS: # Nothing # %DESCRIPTION: # Reads characters from command pipelin and appends them to .msg. #*********************************************************************** proc CommandReadable { f } { global CmdDone set stuff [read $f] .msgs insert end $stuff .msgs see end if {[eof $f]} { set CmdDone 1 } } #*********************************************************************** # %PROCEDURE: CallConfigure # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Executes "./configure" with appropriate arguments # %PRECONDITIONS: # Any preconditions # %POSTCONDITIONS: # Any postconditions # %SIDE EFFECTS: # Any side effects #*********************************************************************** proc CallConfigure {} { global Instdir set bin [$Instdir.bin get] set man [$Instdir.man get] RunCommand "./configure --bindir=$bin --mandir=$man" } #*********************************************************************** # %PROCEDURE: CreateCustomH # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Creates "src/custom.h" from "src/custom.h.in" #*********************************************************************** proc CreateCustomH {} { global Loc Options Config set problem [catch {set in [open "src/custom.h.in" "r"]} err] if {$problem} { Bail "Can't read src/custom.h.in: $err" } set problem [catch {set out [open "src/custom.h" "w"]} err] if {$problem} { Bail "Can't write src/custom.h: $err" } # Retrieve values # The latitude/longitude ones are tied to the scales; we can't # modify them willy-nilly set LAT_DEG $Config(LAT_DEG) set LAT_MIN $Config(LAT_MIN) set LON_DEG $Config(LON_DEG) set LON_MIN $Config(LON_MIN) if {!$Config(NORTHERN_HEMISPHERE)} { set LAT_DEG "-$LAT_DEG" set LAT_MIN "-$LAT_MIN" } if {!$Config(WESTERN_HEMISPHERE)} { set LON_DEG "-$LON_DEG" set LON_MIN "-$LON_MIN" } set Config(LOCATION) [$Loc.location get] switch -- [$Options.page cget -text] { "A4" { set Config(DEFAULT_PAGE) "{\"A4\", 595, 842}" } default { set Config(DEFAULT_PAGE) "{\"Letter\", 612, 792}" } } set Config(DATESEP) [$Options.date cget -text] set Config(TIMESEP) [$Options.time cget -text] switch -- [$Options.char cget -text] { "ISO 8859-1" { set Config(ISOLATIN1) 1 } "ISO 8859-2" { set Config(ISOLATIN2) 1 } "IBM CPI-852" { set Config(IBM852) 1 } "IBM Extended" { set Config(IBMEXTENDED) 1 } } while {[gets $in line] != -1} { switch -glob -- $line { "#define LAT_DEG *" { puts $out "#define LAT_DEG $LAT_DEG" .msgs insert end "#define LAT_DEG $LAT_DEG\n" } "#define LAT_MIN *" { puts $out "#define LAT_MIN $LAT_MIN" .msgs insert end "#define LAT_MIN $LAT_MIN\n" } "#define LON_DEG *" { puts $out "#define LON_DEG $LON_DEG" .msgs insert end "#define LON_DEG $LON_DEG\n" } "#define LON_MIN *" { puts $out "#define LON_MIN $LON_MIN" .msgs insert end "#define LON_MIN $LON_MIN\n" } "#define LOCATION *" { puts $out "#define LOCATION \"$Config(LOCATION)\"" .msgs insert end "#define LOCATION \"$Config(LOCATION)\"\n" } "#define DEFAULT_PAGE *" { puts $out "#define DEFAULT_PAGE $Config(DEFAULT_PAGE)" .msgs insert end "#define DEFAULT_PAGE $Config(DEFAULT_PAGE)\n" } "#define DATESEP *" { puts $out "#define DATESEP '$Config(DATESEP)'" .msgs insert end "#define DATESEP '$Config(DATESEP)'\n" } "#define TIMESEP *" { puts $out "#define TIMESEP '$Config(TIMESEP)'" .msgs insert end "#define TIMESEP '$Config(TIMESEP)'\n" } "#define ISOLATIN1 *" { puts $out "#define ISOLATIN1 $Config(ISOLATIN1)" .msgs insert end "#define ISOLATIN1 $Config(ISOLATIN1)\n" } "#define ISOLATIN2 *" { puts $out "#define ISOLATIN2 $Config(ISOLATIN2)" .msgs insert end "#define ISOLATIN2 $Config(ISOLATIN2)\n" } "#define IBM852 *" { puts $out "#define IBM852 $Config(IBM852)" .msgs insert end "#define IBM852 $Config(IBM852)\n" } "#define IBMEXTENDED *" { puts $out "#define IBMEXTENDED $Config(IBMEXTENDED)" .msgs insert end "#define IBMEXTENDED $Config(IBMEXTENDED)\n" } default { puts $out $line } } } close $in close $out } #*********************************************************************** # %PROCEDURE: CallMake # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Runs "make" with appropriate language definitions #*********************************************************************** proc CallMake {} { global Options set lang [$Options.lang cget -text] switch -- $lang { "German" { set lang GERMAN } "Dutch" { set lang DUTCH } "Finnish" { set lang FINNISH } "French" { set lang FRENCH } "Norwegian" { set lang NORWEGIAN } "Danish" { set lang DANISH } "Polish" { set lang POLISH } "Brazilian Portuguese" { set lang BRAZPORT } "Italian" { set lang ITALIAN } "Romanian" { set lang ROMANIAN } "Spanish" { set lang SPANISH } "Icelandic" { set lang ICELANDIC } default { set lang ENGLISH } } RunCommand "make \"LANGDEF=-DLANG=$lang\"" } # Tabbed notebook code from "Effective Tcl/Tk Programming" # ---------------------------------------------------------------------- # EXAMPLE: tabnotebook that can dial up pages # ---------------------------------------------------------------------- # Effective Tcl/Tk Programming # Mark Harrison, DSC Communications Corp. # Michael McLennan, Bell Labs Innovations for Lucent Technologies # Addison-Wesley Professional Computing Series # ====================================================================== # Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison # ====================================================================== option add *Tabnotebook.tabs.background #666666 widgetDefault option add *Tabnotebook.margin 6 widgetDefault option add *Tabnotebook.tabColor #a6a6a6 widgetDefault option add *Tabnotebook.activeTabColor #d9d9d9 widgetDefault option add *Tabnotebook.tabFont \ -*-helvetica-bold-r-normal--*-120-* widgetDefault proc tabnotebook_create {win} { global tnInfo frame $win -class Tabnotebook canvas $win.tabs -highlightthickness 0 pack $win.tabs -fill x notebook_create $win.notebook pack $win.notebook -expand yes -fill both set tnInfo($win-tabs) "" set tnInfo($win-current) "" set tnInfo($win-pending) "" return $win } proc tabnotebook_page {win name} { global tnInfo set page [notebook_page $win.notebook $name] lappend tnInfo($win-tabs) $name if {$tnInfo($win-pending) == ""} { set id [after idle [list tabnotebook_refresh $win]] set tnInfo($win-pending) $id } return $page } proc tabnotebook_refresh {win} { global tnInfo $win.tabs delete all set margin [option get $win margin Margin] set color [option get $win tabColor Color] set font [option get $win tabFont Font] set x 2 set maxh 0 foreach name $tnInfo($win-tabs) { set id [$win.tabs create text \ [expr $x+$margin+2] [expr -0.5*$margin] \ -anchor sw -text $name -font $font \ -tags [list $name]] set bbox [$win.tabs bbox $id] set wd [expr [lindex $bbox 2]-[lindex $bbox 0]] set ht [expr [lindex $bbox 3]-[lindex $bbox 1]] if {$ht > $maxh} { set maxh $ht } $win.tabs create polygon 0 0 $x 0 \ [expr $x+$margin] [expr -$ht-$margin] \ [expr $x+$margin+$wd] [expr -$ht-$margin] \ [expr $x+$wd+2*$margin] 0 \ 2000 0 2000 10 0 10 \ -outline black -fill $color \ -tags [list $name tab tab-$name] $win.tabs raise $id $win.tabs bind $name \ [list tabnotebook_display $win $name] set x [expr $x+$wd+2*$margin] } set height [expr $maxh+2*$margin] $win.tabs move all 0 $height $win.tabs configure -width $x -height [expr $height+4] if {$tnInfo($win-current) != ""} { tabnotebook_display $win $tnInfo($win-current) } else { tabnotebook_display $win [lindex $tnInfo($win-tabs) 0] } set tnInfo($win-pending) "" } proc tabnotebook_display {win name} { global tnInfo notebook_display $win.notebook $name set normal [option get $win tabColor Color] $win.tabs itemconfigure tab -fill $normal set active [option get $win activeTabColor Color] $win.tabs itemconfigure tab-$name -fill $active $win.tabs raise $name set tnInfo($win-current) $name } # ---------------------------------------------------------------------- # EXAMPLE: simple notebook that can dial up pages # ---------------------------------------------------------------------- # Effective Tcl/Tk Programming # Mark Harrison, DSC Communications Corp. # Michael McLennan, Bell Labs Innovations for Lucent Technologies # Addison-Wesley Professional Computing Series # ====================================================================== # Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison # ====================================================================== option add *Notebook.borderWidth 2 widgetDefault option add *Notebook.relief sunken widgetDefault proc notebook_create {win} { global nbInfo frame $win -class Notebook pack propagate $win 0 set nbInfo($win-count) 0 set nbInfo($win-pages) "" set nbInfo($win-current) "" return $win } proc notebook_page {win name} { global nbInfo set page "$win.page[incr nbInfo($win-count)]" lappend nbInfo($win-pages) $page set nbInfo($win-page-$name) $page frame $page if {$nbInfo($win-count) == 1} { after idle [list notebook_display $win $name] } return $page } proc notebook_display {win name} { global nbInfo set page "" if {[info exists nbInfo($win-page-$name)]} { set page $nbInfo($win-page-$name) } elseif {[winfo exists $win.page$name]} { set page $win.page$name } if {$page == ""} { error "bad notebook page \"$name\"" } notebook_fix_size $win if {$nbInfo($win-current) != ""} { pack forget $nbInfo($win-current) } pack $page -expand yes -fill both set nbInfo($win-current) $page } proc notebook_fix_size {win} { global nbInfo update idletasks set maxw 0 set maxh 0 foreach page $nbInfo($win-pages) { set w [winfo reqwidth $page] if {$w > $maxw} { set maxw $w } set h [winfo reqheight $page] if {$h > $maxh} { set maxh $h } } set bd [$win cget -borderwidth] set maxw [expr $maxw+2*$bd] set maxh [expr $maxh+2*$bd] $win configure -width $maxw -height $maxh } #*********************************************************************** # %PROCEDURE: drawLogo # %ARGUMENTS: # c -- canvas to draw logo in # bg -- background color of canvas # %RETURNS: # Nothing # %DESCRIPTION: # Draws Roaring Penguin logo in a Tcl canvas #*********************************************************************** proc drawLogo { c bg } { set logo_objs { {polygon 558 0 557 0 556 0 554 0 551 0 550 0 549 0 547 0 546 0 544 0 542 1 539 1 537 2 535 3 534 3 533 3 532 3 530 4 528 5 525 6 523 6 522 7 521 7 519 8 516 9 514 10 512 11 510 11 509 12 507 12 507 13 506 13 505 12 502 12 500 11 498 11 497 11 496 11 495 11 493 11 491 12 489 12 488 12 488 13 487 13 485 14 483 15 482 16 481 17 480 19 478 21 477 22 476 23 476 24 475 25 474 26 473 28 472 30 470 33 467 37 464 41 462 45 459 48 457 52 456 54 455 55 454 56 454 57 453 58 452 59 452 61 451 63 449 65 448 68 447 71 445 74 443 77 442 81 440 86 438 90 436 95 435 99 434 103 433 105 433 106 432 107 432 108 432 109 431 111 431 113 430 116 429 121 428 125 427 130 425 135 425 138 424 140 424 142 424 143 424 144 424 145 423 147 423 149 423 152 422 157 421 162 421 167 420 172 420 176 419 180 419 183 419 187 419 189 419 192 418 195 418 196 418 198 418 199 417 199 416 199 415 199 414 199 413 200 412 200 411 200 411 201 410 201 410 202 409 202 409 203 408 203 407 204 407 205 408 205 410 206 413 208 416 209 418 210 419 210 419 211 420 211 421 211 422 212 424 212 426 212 429 213 432 213 435 214 439 214 442 214 444 214 445 214 446 214 447 214 449 214 452 214 457 214 461 214 464 214 466 214 467 214 468 214 469 214 470 214 472 214 474 214 477 213 482 213 486 213 490 212 494 212 497 212 500 211 502 211 505 211 507 211 508 210 509 210 510 210 510 208 511 206 512 203 513 198 514 194 515 189 516 185 517 182 517 179 518 178 518 177 518 176 518 175 519 174 519 171 520 169 520 166 521 163 522 160 522 157 523 153 524 149 524 144 525 139 526 135 526 132 526 130 526 129 526 128 526 127 527 127 527 126 527 124 527 122 527 119 527 115 527 110 527 106 527 102 527 99 527 96 527 95 527 94 527 93 527 92 527 91 527 88 527 85 526 81 526 77 525 72 524 67 524 64 523 60 522 57 521 54 521 51 520 49 520 47 519 45 519 44 518 43 520 42 521 42 523 41 524 40 525 40 526 40 527 40 528 39 530 39 532 39 533 38 534 38 536 38 538 37 539 37 540 37 541 36 543 35 544 34 545 33 546 32 545 32 543 33 542 33 541 34 540 34 539 34 537 34 536 34 534 34 532 34 531 34 530 34 529 34 527 33 525 33 524 33 523 33 522 33 520 32 518 32 517 32 515 31 514 31 514 30 516 29 517 27 519 25 520 24 521 23 521 22 522 22 523 21 524 20 526 19 528 17 530 15 533 14 534 13 535 12 536 12 537 11 538 10 541 9 543 7 545 6 546 6 546 5 547 5 549 4 551 3 553 2 555 1 556 0 557 0 -outline {} -fill \#000000 -width 0} {line 558 0 557 0 556 0 554 0 551 0 550 0 549 0 547 0 546 0 544 0 542 1 539 1 537 2 535 3 534 3 533 3 532 3 530 4 528 5 525 6 523 6 522 7 521 7 519 8 516 9 514 10 512 11 510 11 509 12 507 12 507 13 506 13 505 12 502 12 500 11 498 11 497 11 496 11 495 11 493 11 491 12 489 12 488 12 488 13 487 13 485 14 483 15 482 16 481 17 480 19 478 21 477 22 476 23 476 24 475 25 474 26 473 28 472 30 470 33 467 37 464 41 462 45 459 48 457 52 456 54 455 55 454 56 454 57 453 58 452 59 452 61 451 63 449 65 448 68 447 71 445 74 443 77 442 81 440 86 438 90 436 95 435 99 434 103 433 105 433 106 432 107 432 108 432 109 431 111 431 113 430 116 429 121 428 125 427 130 425 135 425 138 424 140 424 142 424 143 424 144 424 145 423 147 423 149 423 152 422 157 421 162 421 167 420 172 420 176 419 180 419 183 419 187 419 189 419 192 418 195 418 196 418 198 418 199 417 199 416 199 415 199 414 199 413 200 412 200 411 200 411 201 410 201 410 202 409 202 409 203 408 203 407 204 407 205 408 205 410 206 413 208 416 209 418 210 419 210 419 211 420 211 421 211 422 212 424 212 426 212 429 213 432 213 435 214 439 214 442 214 444 214 445 214 446 214 447 214 449 214 452 214 457 214 461 214 464 214 466 214 467 214 468 214 469 214 470 214 472 214 474 214 477 213 482 213 486 213 490 212 494 212 497 212 500 211 502 211 505 211 507 211 508 210 509 210 510 210 510 208 511 206 512 203 513 198 514 194 515 189 516 185 517 182 517 179 518 178 518 177 518 176 518 175 519 174 519 171 520 169 520 166 521 163 522 160 522 157 523 153 524 149 524 144 525 139 526 135 526 132 526 130 526 129 526 128 526 127 527 127 527 126 527 124 527 122 527 119 527 115 527 110 527 106 527 102 527 99 527 96 527 95 527 94 527 93 527 92 527 91 527 88 527 85 526 81 526 77 525 72 524 67 524 64 523 60 522 57 521 54 521 51 520 49 520 47 519 45 519 44 518 43 520 42 521 42 523 41 524 40 525 40 526 40 527 40 528 39 530 39 532 39 533 38 534 38 536 38 538 37 539 37 540 37 541 36 543 35 544 34 545 33 546 32 545 32 543 33 542 33 541 34 540 34 539 34 537 34 536 34 534 34 532 34 531 34 530 34 529 34 527 33 525 33 524 33 523 33 522 33 520 32 518 32 517 32 515 31 514 31 514 30 516 29 517 27 519 25 520 24 521 23 521 22 522 22 523 21 524 20 526 19 528 17 530 15 533 14 534 13 535 12 536 12 537 11 538 10 541 9 543 7 545 6 546 6 546 5 547 5 549 4 551 3 553 2 555 1 556 0 557 0 558 0 -joinstyle bevel} {polygon 490 94 490 95 490 96 489 99 489 103 489 106 488 109 488 111 488 112 488 113 488 115 487 117 487 119 487 121 486 123 485 126 485 130 484 133 483 136 483 137 483 138 483 139 482 139 482 140 482 141 481 144 480 147 479 150 478 153 477 154 477 155 477 156 476 157 476 159 475 161 473 164 472 167 471 170 470 172 468 175 467 176 467 178 466 179 466 180 465 180 465 179 464 177 463 174 462 171 461 169 461 168 461 167 460 166 460 165 460 163 459 161 458 158 458 155 457 152 457 151 457 150 457 149 457 148 456 146 456 143 456 141 456 139 456 138 456 137 456 136 456 134 456 132 456 129 457 126 457 124 457 123 457 121 458 121 458 120 458 121 458 123 458 125 458 127 457 129 457 130 457 131 457 132 458 134 458 136 458 139 458 141 458 143 458 144 459 145 459 148 460 150 460 151 460 152 460 153 461 154 461 155 462 158 462 160 463 162 464 164 464 166 465 167 465 168 465 169 466 169 466 168 467 166 468 163 470 160 470 158 471 157 471 156 472 155 472 154 473 152 474 150 475 147 476 144 477 141 478 139 478 138 479 137 479 136 480 134 480 132 481 129 482 126 483 124 483 122 483 121 484 121 484 120 484 118 485 116 486 112 487 109 487 106 488 103 488 101 489 99 489 97 490 95 490 94 -outline {} -fill $bg -width 0} {line 490 94 490 95 490 96 489 99 489 103 489 106 488 109 488 111 488 112 488 113 488 115 487 117 487 119 487 121 486 123 485 126 485 130 484 133 483 136 483 137 483 138 483 139 482 139 482 140 482 141 481 144 480 147 479 150 478 153 477 154 477 155 477 156 476 157 476 159 475 161 473 164 472 167 471 170 470 172 468 175 467 176 467 178 466 179 466 180 465 180 465 179 464 177 463 174 462 171 461 169 461 168 461 167 460 166 460 165 460 163 459 161 458 158 458 155 457 152 457 151 457 150 457 149 457 148 456 146 456 143 456 141 456 139 456 138 456 137 456 136 456 134 456 132 456 129 457 126 457 124 457 123 457 121 458 121 458 120 458 121 458 123 458 125 458 127 457 129 457 130 457 131 457 132 458 134 458 136 458 139 458 141 458 143 458 144 459 145 459 148 460 150 460 151 460 152 460 153 461 154 461 155 462 158 462 160 463 162 464 164 464 166 465 167 465 168 465 169 466 169 466 168 467 166 468 163 470 160 470 158 471 157 471 156 472 155 472 154 473 152 474 150 475 147 476 144 477 141 478 139 478 138 479 137 479 136 480 134 480 132 481 129 482 126 483 124 483 122 483 121 484 121 484 120 484 118 485 116 486 112 487 109 487 106 488 103 488 101 489 99 489 97 490 95 490 94 -joinstyle bevel} {polygon 503 22 503 23 504 23 504 24 505 24 505 25 505 26 505 27 505 28 505 29 504 29 504 30 503 30 502 30 502 31 501 31 501 30 500 30 499 30 499 29 499 28 499 27 499 26 499 25 499 24 500 24 500 23 501 23 502 22 503 22 -outline {} -fill $bg -width 0} {line 503 22 503 23 504 23 504 24 505 24 505 25 505 26 505 27 505 28 505 29 504 29 504 30 503 30 502 30 502 31 501 31 501 30 500 30 499 30 499 29 499 28 499 27 499 26 499 25 499 24 500 24 500 23 501 23 502 22 503 22 -joinstyle bevel} {polygon 517 44 516 45 515 46 513 47 513 48 512 48 511 48 510 49 508 49 506 50 505 50 504 50 503 50 501 50 498 50 497 51 496 51 495 50 492 50 490 50 487 50 486 49 484 49 483 49 482 48 481 48 481 49 480 51 479 53 479 54 478 55 478 56 477 58 477 59 477 61 477 62 477 63 477 65 477 67 476 68 476 69 477 71 477 72 477 74 477 75 477 76 478 76 479 77 481 77 484 78 485 79 486 79 487 79 488 80 490 81 491 82 493 83 494 84 495 85 496 87 498 88 498 89 499 90 500 92 500 94 500 96 501 98 501 99 501 100 501 101 500 102 500 103 500 104 500 105 499 106 499 107 498 108 498 109 498 110 497 111 497 112 497 113 497 114 497 115 498 115 498 116 499 117 499 118 500 118 500 119 501 120 502 121 502 122 503 122 503 123 502 125 502 128 501 132 501 136 500 139 500 141 500 142 499 143 499 144 499 146 498 148 497 151 496 153 495 156 494 160 493 163 492 165 491 167 491 168 491 169 490 169 490 171 489 174 487 177 486 180 485 182 484 184 484 185 483 185 483 186 482 188 481 190 479 193 478 197 477 199 476 202 475 204 474 206 473 208 472 209 472 210 474 210 476 209 479 209 483 209 488 208 492 207 496 207 499 206 502 206 503 206 504 205 504 204 505 201 506 198 507 193 509 188 510 183 512 179 513 176 514 173 514 172 514 171 514 170 515 169 515 167 516 165 516 162 517 160 518 157 518 154 519 150 520 146 521 142 521 137 522 133 523 129 523 126 523 124 523 122 524 122 524 121 524 120 524 118 524 116 524 113 524 109 524 105 525 101 525 97 525 94 525 92 525 91 525 90 525 89 525 88 525 87 524 85 524 82 524 78 523 74 523 70 522 66 522 62 521 59 521 56 520 54 519 51 519 49 518 47 518 46 518 45 518 44 -outline {} -fill $bg -width 0} {line 517 44 516 45 515 46 513 47 513 48 512 48 511 48 510 49 508 49 506 50 505 50 504 50 503 50 501 50 498 50 497 51 496 51 495 50 492 50 490 50 487 50 486 49 484 49 483 49 482 48 481 48 481 49 480 51 479 53 479 54 478 55 478 56 477 58 477 59 477 61 477 62 477 63 477 65 477 67 476 68 476 69 477 71 477 72 477 74 477 75 477 76 478 76 479 77 481 77 484 78 485 79 486 79 487 79 488 80 490 81 491 82 493 83 494 84 495 85 496 87 498 88 498 89 499 90 500 92 500 94 500 96 501 98 501 99 501 100 501 101 500 102 500 103 500 104 500 105 499 106 499 107 498 108 498 109 498 110 497 111 497 112 497 113 497 114 497 115 498 115 498 116 499 117 499 118 500 118 500 119 501 120 502 121 502 122 503 122 503 123 502 125 502 128 501 132 501 136 500 139 500 141 500 142 499 143 499 144 499 146 498 148 497 151 496 153 495 156 494 160 493 163 492 165 491 167 491 168 491 169 490 169 490 171 489 174 487 177 486 180 485 182 484 184 484 185 483 185 483 186 482 188 481 190 479 193 478 197 477 199 476 202 475 204 474 206 473 208 472 209 472 210 474 210 476 209 479 209 483 209 488 208 492 207 496 207 499 206 502 206 503 206 504 205 504 204 505 201 506 198 507 193 509 188 510 183 512 179 513 176 514 173 514 172 514 171 514 170 515 169 515 167 516 165 516 162 517 160 518 157 518 154 519 150 520 146 521 142 521 137 522 133 523 129 523 126 523 124 523 122 524 122 524 121 524 120 524 118 524 116 524 113 524 109 524 105 525 101 525 97 525 94 525 92 525 91 525 90 525 89 525 88 525 87 524 85 524 82 524 78 523 74 523 70 522 66 522 62 521 59 521 56 520 54 519 51 519 49 518 47 518 46 518 45 518 44 517 44 -joinstyle bevel} {polygon 11 126 12 126 13 126 16 126 19 126 23 126 27 126 32 126 36 126 39 126 41 126 43 126 45 126 47 126 50 127 51 127 52 127 53 128 54 128 56 129 57 130 58 132 59 132 59 133 60 134 61 135 61 137 62 138 62 139 62 140 62 142 62 144 62 145 62 147 62 148 62 149 62 150 61 152 61 154 61 155 61 156 60 157 60 158 59 159 58 161 57 162 57 163 56 164 55 165 54 166 53 167 51 168 49 169 48 169 47 170 46 170 47 171 49 171 51 172 52 172 53 173 54 174 55 175 56 177 56 178 57 180 57 181 57 182 57 183 57 184 57 185 57 187 57 189 57 190 57 191 56 192 56 194 56 196 56 199 56 200 56 201 56 202 55 203 55 205 55 206 55 207 55 208 55 209 56 209 56 210 56 211 57 212 58 212 58 213 57 213 56 213 55 213 51 213 47 213 43 213 40 213 38 213 37 213 37 212 37 211 36 210 36 209 36 208 36 207 36 206 36 205 37 204 37 203 37 202 37 201 37 199 37 198 37 197 37 196 37 195 37 194 38 192 38 189 38 188 38 187 38 186 38 185 38 184 38 182 37 181 37 180 37 179 36 179 36 178 35 178 34 177 33 177 32 177 31 177 30 177 28 177 26 177 24 177 24 178 24 179 24 182 23 186 23 190 22 195 22 200 21 205 21 208 20 211 20 213 19 213 17 213 14 213 10 213 7 213 4 213 2 213 1 213 1 212 1 211 2 208 2 205 2 201 3 196 4 190 4 184 5 177 6 169 7 162 8 155 9 149 9 143 10 138 10 134 11 131 11 129 11 127 11 126 -outline {} -fill \#000000 -width 0} {polygon 26 163 27 163 29 163 31 163 32 163 33 162 35 162 36 162 37 161 38 161 39 160 40 159 40 158 41 157 42 156 42 154 43 153 43 152 43 151 43 150 43 149 43 148 43 147 43 146 42 145 42 144 42 143 41 143 41 142 40 142 40 141 39 141 38 141 37 141 36 140 35 140 34 140 33 140 31 140 30 140 29 140 28 141 28 142 28 145 28 148 27 151 27 155 26 158 26 161 26 162 26 163 -outline {} -fill \#000000 -width 0} {line 11 126 12 126 13 126 16 126 19 126 23 126 27 126 32 126 36 126 39 126 41 126 43 126 45 126 47 126 50 127 51 127 52 127 53 128 54 128 56 129 57 130 58 132 59 132 59 133 60 134 61 135 61 137 62 138 62 139 62 140 62 142 62 144 62 145 62 147 62 148 62 149 62 150 61 152 61 154 61 155 61 156 60 157 60 158 59 159 58 161 57 162 57 163 56 164 55 165 54 166 53 167 51 168 49 169 48 169 47 170 46 170 47 171 49 171 51 172 52 172 53 173 54 174 55 175 56 177 56 178 57 180 57 181 57 182 57 183 57 184 57 185 57 187 57 189 57 190 57 191 56 192 56 194 56 196 56 199 56 200 56 201 56 202 55 203 55 205 55 206 55 207 55 208 55 209 56 209 56 210 56 211 57 212 58 212 58 213 57 213 56 213 55 213 51 213 47 213 43 213 40 213 38 213 37 213 37 212 37 211 36 210 36 209 36 208 36 207 36 206 36 205 37 204 37 203 37 202 37 201 37 199 37 198 37 197 37 196 37 195 37 194 38 192 38 189 38 188 38 187 38 186 38 185 38 184 38 182 37 181 37 180 37 179 36 179 36 178 35 178 34 177 33 177 32 177 31 177 30 177 28 177 26 177 24 177 24 178 24 179 24 182 23 186 23 190 22 195 22 200 21 205 21 208 20 211 20 213 19 213 17 213 14 213 10 213 7 213 4 213 2 213 1 213 1 212 1 211 2 208 2 205 2 201 3 196 4 190 4 184 5 177 6 169 7 162 8 155 9 149 9 143 10 138 10 134 11 131 11 129 11 127 11 126 -joinstyle bevel} {polygon 26 163 27 163 29 163 31 163 32 163 33 162 35 162 36 162 37 161 38 161 39 160 40 159 40 158 41 157 42 156 42 154 43 153 43 152 43 151 43 150 43 149 43 148 43 147 43 146 42 145 42 144 42 143 41 143 41 142 40 142 40 141 39 141 38 141 37 141 36 140 35 140 34 140 33 140 31 140 30 140 29 140 28 141 28 142 28 145 28 148 27 151 27 155 26 158 26 161 26 162 26 163 -outline {} -fill $bg -width 0} {polygon 90 215 89 215 86 214 84 214 81 213 79 213 78 213 77 213 77 212 75 212 74 211 72 209 70 207 69 205 68 204 68 203 68 202 67 202 67 200 66 198 66 195 66 193 66 192 66 191 66 190 66 188 66 185 66 182 66 180 66 177 66 175 66 174 67 172 67 171 67 170 67 169 67 167 68 165 68 162 68 159 69 156 69 155 69 154 70 152 70 151 70 149 71 147 72 144 73 142 74 139 75 138 75 137 76 136 76 135 77 134 79 132 81 130 82 129 83 129 83 128 84 128 85 127 88 126 91 125 93 125 95 124 97 124 99 124 100 124 101 124 102 124 104 125 107 125 110 126 112 126 113 126 114 127 115 127 116 128 117 129 118 130 120 131 121 133 122 135 123 136 123 137 123 138 123 139 124 141 124 143 125 146 125 148 125 149 125 150 125 152 125 156 125 159 124 162 124 164 124 166 124 168 124 169 123 169 123 170 123 171 123 173 122 177 122 180 122 182 121 183 121 184 121 185 121 187 120 189 120 191 119 193 118 196 117 199 116 200 116 201 116 202 115 203 114 204 112 206 111 208 109 209 109 210 108 210 107 211 106 211 103 213 100 213 98 214 96 214 94 215 92 215 91 215 90 215 -outline {} -fill \#000000 -width 0} {polygon 91 201 92 201 94 200 95 200 96 200 96 199 97 198 98 197 99 196 99 195 100 194 100 193 100 191 101 189 101 188 101 187 102 185 102 182 103 179 103 177 103 175 103 173 104 171 104 170 104 169 104 168 104 166 104 163 105 160 105 158 105 157 105 156 105 154 105 153 106 150 106 148 105 146 105 145 105 144 105 143 105 142 104 141 104 140 103 139 101 138 100 138 99 138 98 138 96 138 95 139 94 139 94 140 93 141 92 142 91 143 91 144 91 145 91 146 90 148 89 150 89 151 89 152 89 154 88 157 88 160 87 162 87 164 87 166 87 168 86 169 86 170 86 171 86 173 86 176 85 179 85 181 85 182 85 183 85 185 85 186 85 189 85 191 85 193 85 194 85 195 85 196 86 197 86 198 86 199 87 199 88 200 89 201 90 201 91 201 -outline {} -fill $bg -width 0} {line 90 215 89 215 86 214 84 214 81 213 79 213 78 213 77 213 77 212 75 212 74 211 72 209 70 207 69 205 68 204 68 203 68 202 67 202 67 200 66 198 66 195 66 193 66 192 66 191 66 190 66 188 66 185 66 182 66 180 66 177 66 175 66 174 67 172 67 171 67 170 67 169 67 167 68 165 68 162 68 159 69 156 69 155 69 154 70 152 70 151 70 149 71 147 72 144 73 142 74 139 75 138 75 137 76 136 76 135 77 134 79 132 81 130 82 129 83 129 83 128 84 128 85 127 88 126 91 125 93 125 95 124 97 124 99 124 100 124 101 124 102 124 104 125 107 125 110 126 112 126 113 126 114 127 115 127 116 128 117 129 118 130 120 131 121 133 122 135 123 136 123 137 123 138 123 139 124 141 124 143 125 146 125 148 125 149 125 150 125 152 125 156 125 159 124 162 124 164 124 166 124 168 124 169 123 169 123 170 123 171 123 173 122 177 122 180 122 182 121 183 121 184 121 185 121 187 120 189 120 191 119 193 118 196 117 199 116 200 116 201 116 202 115 203 114 204 112 206 111 208 109 209 109 210 108 210 107 211 106 211 103 213 100 213 98 214 96 214 94 215 92 215 91 215 90 215 -joinstyle bevel} {polygon 149 126 173 126 182 213 163 213 162 197 142 197 138 213 118 213 -outline {} -fill \#000000 -width 0} {polygon 158 142 147 181 161 181 -outline {} -fill \#000000 -width 0} {line 149 126 173 126 182 213 163 213 162 197 142 197 138 213 118 213 149 126} {polygon 158 142 147 181 161 181 -outline {} -fill $bg -width 0} {polygon 196 126 197 126 198 126 201 126 204 126 208 126 212 126 217 126 221 126 224 126 226 126 228 126 230 126 232 126 235 127 236 127 237 127 238 128 239 128 241 129 242 130 244 132 244 133 245 133 245 134 246 135 246 137 247 138 247 139 247 140 247 142 247 144 247 145 247 147 247 148 247 149 247 150 246 152 246 154 246 155 246 156 245 157 245 158 244 159 244 161 242 162 242 163 241 164 240 165 239 166 238 167 236 168 235 169 233 169 232 169 232 170 231 170 232 171 234 171 236 172 237 172 238 172 238 173 239 174 240 175 241 177 241 178 242 180 242 181 242 182 242 183 242 184 242 185 242 187 242 189 242 190 242 191 241 192 241 194 241 196 241 199 241 200 241 201 241 202 241 203 240 205 240 206 240 207 240 208 241 208 241 209 241 210 241 211 242 212 243 212 243 213 242 213 240 213 236 213 232 213 228 213 225 213 223 213 222 213 222 212 222 211 221 210 221 209 221 208 221 207 221 206 221 205 221 204 221 203 221 202 222 201 222 199 222 198 222 197 222 196 222 195 222 194 223 192 223 189 223 188 223 187 223 186 223 185 223 184 223 182 222 181 222 180 222 179 221 178 220 178 218 177 217 177 216 177 215 177 213 177 211 177 209 177 209 178 209 179 209 182 208 186 208 190 207 195 206 200 206 205 206 208 205 211 205 213 204 213 202 213 199 213 196 213 192 213 189 213 187 213 186 213 186 212 186 211 187 208 187 205 188 201 188 196 189 190 190 184 190 177 191 169 192 162 193 155 194 149 194 143 195 138 196 134 196 131 196 129 196 127 196 126 -outline {} -fill \#000000 -width 0} {polygon 211 163 212 163 214 163 216 163 217 163 218 162 220 162 221 162 222 161 223 161 224 160 225 159 225 158 226 157 227 157 227 156 227 154 228 153 228 152 228 151 228 150 228 149 228 148 228 147 228 146 227 145 227 144 227 143 226 142 225 142 225 141 224 141 223 141 222 141 221 140 220 140 219 140 218 140 217 140 215 140 214 140 214 141 213 142 213 145 213 148 212 151 212 155 212 158 211 161 211 162 211 163 -outline {} -fill \#000000 -width 0} {line 196 126 197 126 198 126 201 126 204 126 208 126 212 126 217 126 221 126 224 126 226 126 228 126 230 126 232 126 235 127 236 127 237 127 238 128 239 128 241 129 242 130 244 132 244 133 245 133 245 134 246 135 246 137 247 138 247 139 247 140 247 142 247 144 247 145 247 147 247 148 247 149 247 150 246 152 246 154 246 155 246 156 245 157 245 158 244 159 244 161 242 162 242 163 241 164 240 165 239 166 238 167 236 168 235 169 233 169 232 169 232 170 231 170 232 171 234 171 236 172 237 172 238 172 238 173 239 174 240 175 241 177 241 178 242 180 242 181 242 182 242 183 242 184 242 185 242 187 242 189 242 190 242 191 241 192 241 194 241 196 241 199 241 200 241 201 241 202 241 203 240 205 240 206 240 207 240 208 241 208 241 209 241 210 241 211 242 212 243 212 243 213 242 213 240 213 236 213 232 213 228 213 225 213 223 213 222 213 222 212 222 211 221 210 221 209 221 208 221 207 221 206 221 205 221 204 221 203 221 202 222 201 222 199 222 198 222 197 222 196 222 195 222 194 223 192 223 189 223 188 223 187 223 186 223 185 223 184 223 182 222 181 222 180 222 179 221 178 220 178 218 177 217 177 216 177 215 177 213 177 211 177 209 177 209 178 209 179 209 182 208 186 208 190 207 195 206 200 206 205 206 208 205 211 205 213 204 213 202 213 199 213 196 213 192 213 189 213 187 213 186 213 186 212 186 211 187 208 187 205 188 201 188 196 189 190 190 184 190 177 191 169 192 162 193 155 194 149 194 143 195 138 196 134 196 131 196 129 196 127 196 126 -joinstyle bevel} {polygon 211 163 212 163 214 163 216 163 217 163 218 162 220 162 221 162 222 161 223 161 224 160 225 159 225 158 226 157 227 157 227 156 227 154 228 153 228 152 228 151 228 150 228 149 228 148 228 147 228 146 227 145 227 144 227 143 226 142 225 142 225 141 224 141 223 141 222 141 221 140 220 140 219 140 218 140 217 140 215 140 214 140 214 141 213 142 213 145 213 148 212 151 212 155 212 158 211 161 211 162 211 163 -outline {} -fill $bg -width 0} {polygon 259 126 278 126 268 213 249 213 -outline {} -fill \#000000 -width 0} {line 259 126 278 126 268 213 249 213 259 126} {polygon 288 126 310 126 319 183 326 126 343 126 333 213 311 213 302 153 295 213 278 213 -outline {} -fill \#000000 -width 0} {line 288 126 310 126 319 183 326 126 343 126 333 213 311 213 302 153 295 213 278 213 288 126} {polygon 383 152 384 151 384 150 384 149 384 148 384 147 384 146 384 145 384 144 383 143 383 142 383 141 382 140 382 139 381 139 380 138 379 138 378 138 377 138 376 138 375 139 374 139 373 139 373 140 372 141 371 142 370 144 370 145 369 145 369 146 368 148 368 151 368 152 368 153 367 154 367 157 366 160 366 162 366 164 366 166 365 168 365 169 365 170 365 171 365 173 365 176 364 179 364 181 364 182 364 183 364 185 364 186 364 189 364 191 364 193 364 194 364 195 364 196 364 197 365 198 365 199 366 199 366 200 368 201 369 201 370 201 371 201 373 201 373 200 374 200 375 200 375 199 376 198 377 197 377 196 378 196 378 195 379 193 379 192 379 191 380 189 380 187 380 186 381 185 381 184 381 183 381 182 381 181 381 180 380 180 377 180 374 180 373 180 372 180 373 179 373 176 373 173 374 170 374 168 374 166 375 166 376 166 379 166 383 166 387 166 392 166 395 166 398 166 400 166 401 166 401 167 400 168 400 171 400 174 399 179 398 184 398 190 397 196 397 201 396 205 395 209 395 211 395 213 394 213 392 213 389 213 385 213 383 213 382 213 382 212 382 209 382 207 383 205 382 205 381 206 380 208 380 209 379 209 378 210 377 211 376 212 375 213 374 213 372 214 371 214 370 214 368 215 367 215 365 215 364 215 363 215 361 214 359 214 356 213 355 213 354 213 353 213 352 212 351 211 349 209 348 207 346 205 346 204 346 203 345 201 345 198 344 196 344 194 344 193 344 192 344 190 344 186 344 184 344 181 345 179 345 177 345 175 345 174 345 172 345 171 346 171 346 169 346 166 347 163 347 160 347 158 347 156 348 156 348 155 348 153 348 152 349 150 349 148 350 145 351 142 352 140 353 138 353 137 354 137 354 136 355 134 357 132 359 131 360 130 361 129 362 128 364 127 366 126 369 125 371 125 374 124 376 124 378 124 379 124 380 124 381 124 383 125 386 125 388 125 390 126 391 126 392 126 392 127 394 127 395 128 397 129 398 131 400 133 400 134 400 135 401 136 401 138 402 140 402 141 402 142 402 143 402 146 402 148 402 150 402 151 402 152 401 152 399 152 396 152 393 152 389 152 386 152 384 152 -outline {} -fill \#000000 -width 0} {line 383 152 384 151 384 150 384 149 384 148 384 147 384 146 384 145 384 144 383 143 383 142 383 141 382 140 382 139 381 139 380 138 379 138 378 138 377 138 376 138 375 139 374 139 373 139 373 140 372 141 371 142 370 144 370 145 369 145 369 146 368 148 368 151 368 152 368 153 367 154 367 157 366 160 366 162 366 164 366 166 365 168 365 169 365 170 365 171 365 173 365 176 364 179 364 181 364 182 364 183 364 185 364 186 364 189 364 191 364 193 364 194 364 195 364 196 364 197 365 198 365 199 366 199 366 200 368 201 369 201 370 201 371 201 373 201 373 200 374 200 375 200 375 199 376 198 377 197 377 196 378 196 378 195 379 193 379 192 379 191 380 189 380 187 380 186 381 185 381 184 381 183 381 182 381 181 381 180 380 180 377 180 374 180 373 180 372 180 373 179 373 176 373 173 374 170 374 168 374 166 375 166 376 166 379 166 383 166 387 166 392 166 395 166 398 166 400 166 401 166 401 167 400 168 400 171 400 174 399 179 398 184 398 190 397 196 397 201 396 205 395 209 395 211 395 213 394 213 392 213 389 213 385 213 383 213 382 213 382 212 382 209 382 207 383 205 382 205 381 206 380 208 380 209 379 209 378 210 377 211 376 212 375 213 374 213 372 214 371 214 370 214 368 215 367 215 365 215 364 215 363 215 361 214 359 214 356 213 355 213 354 213 353 213 352 212 351 211 349 209 348 207 346 205 346 204 346 203 345 201 345 198 344 196 344 194 344 193 344 192 344 190 344 186 344 184 344 181 345 179 345 177 345 175 345 174 345 172 345 171 346 171 346 169 346 166 347 163 347 160 347 158 347 156 348 156 348 155 348 153 348 152 349 150 349 148 350 145 351 142 352 140 353 138 353 137 354 137 354 136 355 134 357 132 359 131 360 130 361 129 362 128 364 127 366 126 369 125 371 125 374 124 376 124 378 124 379 124 380 124 381 124 383 125 386 125 388 125 390 126 391 126 392 126 392 127 394 127 395 128 397 129 398 131 400 133 400 134 400 135 401 136 401 138 402 140 402 141 402 142 402 143 402 146 402 148 402 150 402 151 402 152 401 152 399 152 396 152 393 152 389 152 386 152 384 152 383 152 -joinstyle bevel} {polygon 118 229 119 229 121 229 124 229 128 229 133 229 137 229 142 229 145 229 146 229 147 229 148 229 150 229 152 230 155 230 156 230 157 231 158 231 159 231 160 232 162 233 163 235 165 236 165 237 166 237 166 238 166 239 167 241 167 243 168 243 168 244 168 245 168 247 168 249 168 251 168 252 168 253 168 254 167 255 167 258 166 261 166 262 166 263 165 264 165 265 164 267 162 269 161 271 160 272 159 273 157 274 155 275 154 276 153 276 153 277 152 277 149 278 147 278 145 279 143 279 142 279 140 279 139 279 137 279 135 279 132 279 131 279 130 280 130 281 130 283 130 286 129 291 128 295 128 300 127 304 127 307 127 309 127 310 127 311 126 311 124 311 121 311 117 311 113 311 110 311 109 311 108 311 108 310 108 308 108 305 109 301 109 297 110 291 111 284 112 277 113 270 114 263 115 255 115 249 116 243 117 238 117 235 118 232 118 230 118 229 -outline {} -fill \#1892ff -width 0} {polygon 132 265 133 265 134 265 136 265 137 265 138 265 139 265 140 264 141 264 142 264 143 264 143 263 144 263 145 262 146 262 146 261 146 260 147 259 148 258 148 256 148 255 148 254 148 253 148 252 148 251 148 250 148 249 148 248 147 247 147 246 146 245 145 244 144 244 143 243 142 243 141 243 140 243 138 243 137 243 135 243 135 244 135 245 134 247 134 250 134 254 133 257 133 261 133 263 133 264 132 265 -outline {} -fill \#1892ff -width 0} {line 118 229 119 229 121 229 124 229 128 229 133 229 137 229 142 229 145 229 146 229 147 229 148 229 150 229 152 230 155 230 156 230 157 231 158 231 159 231 160 232 162 233 163 235 165 236 165 237 166 237 166 238 166 239 167 241 167 243 168 243 168 244 168 245 168 247 168 249 168 251 168 252 168 253 168 254 167 255 167 258 166 261 166 262 166 263 165 264 165 265 164 267 162 269 161 271 160 272 159 273 157 274 155 275 154 276 153 276 153 277 152 277 149 278 147 278 145 279 143 279 142 279 140 279 139 279 137 279 135 279 132 279 131 279 130 280 130 281 130 283 130 286 129 291 128 295 128 300 127 304 127 307 127 309 127 310 127 311 126 311 124 311 121 311 117 311 113 311 110 311 109 311 108 311 108 310 108 308 108 305 109 301 109 297 110 291 111 284 112 277 113 270 114 263 115 255 115 249 116 243 117 238 117 235 118 232 118 230 118 229 -joinstyle bevel -fill \#1892ff} {polygon 176 229 223 229 221 244 193 244 191 261 217 261 215 277 189 277 187 295 215 295 214 311 166 311 -outline {} -fill \#1892ff -width 0} {line 176 229 223 229 221 244 193 244 191 261 217 261 215 277 189 277 187 295 215 295 214 311 166 311 176 229 -fill \#1892ff} {polygon 232 229 254 229 263 282 270 229 288 229 277 311 256 311 246 254 239 311 222 311 -outline {} -fill \#1892ff -width 0} {line 232 229 254 229 263 282 270 229 288 229 277 311 256 311 246 254 239 311 222 311 232 229 -fill \#1892ff} {polygon 328 254 328 253 328 251 328 250 328 249 328 248 328 247 328 246 328 245 328 244 327 243 327 242 326 242 325 241 324 241 323 240 322 240 321 240 319 241 318 241 317 242 316 243 315 244 314 246 314 247 314 248 313 250 312 252 312 253 312 254 312 256 311 259 311 261 311 263 310 265 310 267 310 268 310 270 310 271 309 273 309 276 309 279 308 281 308 282 308 283 308 284 308 286 308 288 308 290 308 292 308 293 308 294 309 296 309 297 310 298 311 299 312 300 313 300 314 300 315 300 316 300 317 299 318 299 319 299 319 298 320 298 321 297 322 296 322 295 323 293 323 292 324 291 324 289 325 287 325 285 325 284 325 283 325 282 326 282 326 281 326 280 325 280 324 280 321 280 319 280 317 280 317 279 317 276 318 273 318 270 318 268 319 267 321 267 324 267 327 267 332 267 336 267 340 267 343 267 344 267 345 267 345 268 345 269 344 271 344 274 343 279 343 284 342 289 341 294 341 300 340 304 340 307 340 309 339 310 339 311 338 311 336 311 333 311 330 311 328 311 327 311 326 311 327 310 327 307 327 305 327 304 327 303 326 304 325 306 324 307 324 308 323 308 322 309 321 310 320 311 319 311 318 311 317 312 316 312 315 312 314 312 313 312 311 313 310 313 309 313 308 313 307 313 306 312 303 312 301 311 299 311 298 311 298 310 296 310 295 309 294 308 292 306 291 304 290 302 290 301 290 300 289 297 289 295 289 293 289 292 289 291 289 289 289 286 289 283 289 280 289 278 289 275 290 274 290 273 290 272 290 271 290 270 291 267 291 264 291 261 292 259 292 258 292 257 292 256 292 255 293 253 293 252 294 249 295 247 296 244 297 242 298 240 298 239 299 238 300 237 301 235 303 234 304 232 305 232 306 231 308 230 311 229 313 228 316 228 318 227 320 227 322 227 323 227 324 227 325 227 327 228 330 228 333 229 335 229 336 229 337 229 338 230 340 231 341 232 343 234 344 236 345 237 345 238 346 240 346 242 347 244 347 246 347 247 347 250 347 251 346 252 346 253 346 254 345 254 343 254 341 254 337 254 334 254 331 254 329 254 328 254 -outline {} -fill \#1892ff -width 0} {line 328 254 328 253 328 251 328 250 328 249 328 248 328 247 328 246 328 245 328 244 327 243 327 242 326 242 325 241 324 241 323 240 322 240 321 240 319 241 318 241 317 242 316 243 315 244 314 246 314 247 314 248 313 250 312 252 312 253 312 254 312 256 311 259 311 261 311 263 310 265 310 267 310 268 310 270 310 271 309 273 309 276 309 279 308 281 308 282 308 283 308 284 308 286 308 288 308 290 308 292 308 293 308 294 309 296 309 297 310 298 311 299 312 300 313 300 314 300 315 300 316 300 317 299 318 299 319 299 319 298 320 298 321 297 322 296 322 295 323 293 323 292 324 291 324 289 325 287 325 285 325 284 325 283 325 282 326 282 326 281 326 280 325 280 324 280 321 280 319 280 317 280 317 279 317 276 318 273 318 270 318 268 319 267 321 267 324 267 327 267 332 267 336 267 340 267 343 267 344 267 345 267 345 268 345 269 344 271 344 274 343 279 343 284 342 289 341 294 341 300 340 304 340 307 340 309 339 310 339 311 338 311 336 311 333 311 330 311 328 311 327 311 326 311 327 310 327 307 327 305 327 304 327 303 326 304 325 306 324 307 324 308 323 308 322 309 321 310 320 311 319 311 318 311 317 312 316 312 315 312 314 312 313 312 311 313 310 313 309 313 308 313 307 313 306 312 303 312 301 311 299 311 298 311 298 310 296 310 295 309 294 308 292 306 291 304 290 302 290 301 290 300 289 297 289 295 289 293 289 292 289 291 289 289 289 286 289 283 289 280 289 278 289 275 290 274 290 273 290 272 290 271 290 270 291 267 291 264 291 261 292 259 292 258 292 257 292 256 292 255 293 253 293 252 294 249 295 247 296 244 297 242 298 240 298 239 299 238 300 237 301 235 303 234 304 232 305 232 306 231 308 230 311 229 313 228 316 228 318 227 320 227 322 227 323 227 324 227 325 227 327 228 330 228 333 229 335 229 336 229 337 229 338 230 340 231 341 232 343 234 344 236 345 237 345 238 346 240 346 242 347 244 347 246 347 247 347 250 347 251 346 252 346 253 346 254 345 254 343 254 341 254 337 254 334 254 331 254 329 254 328 254 -joinstyle bevel -fill \#1892ff} {polygon 405 284 404 286 404 289 403 291 403 293 403 294 402 295 402 297 401 299 400 301 398 303 397 304 397 305 396 306 394 307 392 309 391 309 391 310 390 310 389 310 386 311 384 312 381 312 380 312 378 313 376 313 375 313 374 313 372 312 369 312 367 312 365 311 364 311 363 311 362 310 360 310 358 309 356 307 355 306 354 305 354 304 353 303 353 301 352 299 352 298 352 297 351 295 351 293 351 290 351 288 352 286 352 285 352 284 352 283 352 282 352 280 353 277 353 273 354 268 355 262 355 256 356 250 357 245 357 240 358 236 358 233 359 231 359 229 360 229 362 229 365 229 368 229 372 229 375 229 377 229 378 229 377 230 377 232 377 234 376 238 376 242 375 247 375 253 374 259 373 265 372 271 372 276 371 280 371 284 370 287 370 288 370 289 370 290 370 291 370 292 370 293 370 294 370 295 370 296 371 297 372 298 372 299 373 299 374 299 374 300 375 300 376 300 377 300 378 300 379 299 380 299 381 299 381 298 382 297 383 297 383 296 383 295 384 295 384 294 384 293 385 292 385 291 385 290 385 289 385 288 386 287 386 284 386 280 387 276 388 271 388 265 389 259 390 253 390 247 391 242 392 238 392 234 392 232 393 230 393 229 394 229 396 229 399 229 402 229 406 229 409 229 411 229 412 229 412 231 411 233 411 236 410 240 410 245 409 250 408 256 407 262 407 268 406 273 406 277 405 280 405 282 405 283 -outline {} -fill \#1892ff -width 0} {line 405 284 404 286 404 289 403 291 403 293 403 294 402 295 402 297 401 299 400 301 398 303 397 304 397 305 396 306 394 307 392 309 391 309 391 310 390 310 389 310 386 311 384 312 381 312 380 312 378 313 376 313 375 313 374 313 372 312 369 312 367 312 365 311 364 311 363 311 362 310 360 310 358 309 356 307 355 306 354 305 354 304 353 303 353 301 352 299 352 298 352 297 351 295 351 293 351 290 351 288 352 286 352 285 352 284 352 283 352 282 352 280 353 277 353 273 354 268 355 262 355 256 356 250 357 245 357 240 358 236 358 233 359 231 359 229 360 229 362 229 365 229 368 229 372 229 375 229 377 229 378 229 377 230 377 232 377 234 376 238 376 242 375 247 375 253 374 259 373 265 372 271 372 276 371 280 371 284 370 287 370 288 370 289 370 290 370 291 370 292 370 293 370 294 370 295 370 296 371 297 372 298 372 299 373 299 374 299 374 300 375 300 376 300 377 300 378 300 379 299 380 299 381 299 381 298 382 297 383 297 383 296 383 295 384 295 384 294 384 293 385 292 385 291 385 290 385 289 385 288 386 287 386 284 386 280 387 276 388 271 388 265 389 259 390 253 390 247 391 242 392 238 392 234 392 232 393 230 393 229 394 229 396 229 399 229 402 229 406 229 409 229 411 229 412 229 412 231 411 233 411 236 410 240 410 245 409 250 408 256 407 262 407 268 406 273 406 277 405 280 405 282 405 283 405 284 -joinstyle bevel -fill \#1892ff} {polygon 421 229 439 229 429 311 410 311 -outline {} -fill \#1892ff -width 0} {line 421 229 439 229 429 311 410 311 421 229 -fill \#1892ff} {polygon 449 229 471 229 480 282 487 229 504 229 494 311 473 311 463 254 456 311 439 311 -outline {} -fill \#1892ff -width 0} {line 449 229 471 229 480 282 487 229 504 229 494 311 473 311 463 254 456 311 439 311 449 229 -fill \#1892ff} {polygon 114 354 114 355 114 356 114 357 114 358 114 359 115 359 115 360 116 360 117 360 118 360 119 359 119 358 120 358 120 357 120 356 119 355 119 354 118 353 117 352 116 352 115 351 114 350 113 350 112 349 110 348 109 347 109 346 108 345 108 343 107 342 107 341 107 340 107 339 107 338 108 337 108 336 108 335 109 334 109 333 110 333 110 332 111 331 112 331 113 331 114 330 115 330 116 330 117 330 118 330 119 330 120 330 121 331 122 331 123 332 124 332 124 333 125 334 125 335 125 336 126 336 126 337 126 338 126 339 126 340 125 340 123 340 121 340 119 340 119 339 119 338 119 337 119 336 118 336 118 335 117 335 116 335 116 336 115 336 115 337 114 337 114 338 114 339 115 340 115 341 115 342 116 343 117 343 118 344 120 345 121 345 122 346 123 347 124 347 124 348 125 349 126 351 126 352 126 353 126 354 126 355 126 356 126 358 126 359 126 360 125 361 125 362 124 363 123 364 122 364 122 365 121 365 120 365 119 366 118 366 117 366 116 366 115 366 114 365 113 365 112 365 111 364 110 364 109 363 108 362 108 361 108 360 107 359 107 358 107 357 107 356 107 355 107 354 108 354 110 354 112 354 113 354 -outline {} -fill \#000000 -width 0} {polygon 152 366 151 365 149 365 148 365 147 364 146 364 145 363 144 361 143 360 143 359 143 357 142 357 142 356 142 354 142 352 142 351 142 349 142 348 142 347 142 345 142 343 142 342 142 341 142 340 143 339 143 337 143 336 144 335 144 334 145 333 146 332 146 331 148 331 149 330 150 330 151 330 152 330 154 330 155 331 157 331 158 332 159 333 160 334 161 335 161 336 161 337 162 339 162 340 162 341 162 342 162 344 162 345 162 346 162 347 162 348 162 349 162 351 162 352 162 353 162 354 162 355 162 357 161 358 161 360 161 361 160 362 159 363 159 364 158 364 157 365 155 365 154 366 153 366 152 366 -outline {} -fill \#000000 -width 0} {polygon 152 360 153 360 154 360 154 359 155 358 155 357 155 356 155 355 155 354 155 353 155 351 155 350 155 349 155 348 155 346 155 344 155 343 155 342 155 341 155 339 155 338 154 337 154 336 153 336 153 335 152 335 152 336 151 336 150 336 150 337 150 338 149 338 149 339 149 340 149 341 149 342 149 343 149 345 149 346 149 347 149 348 149 349 149 351 149 352 149 353 149 354 149 355 149 356 149 357 149 358 150 358 150 359 151 360 152 360 -outline {} -fill $bg -width 0} {polygon 179 331 195 331 195 337 185 337 185 344 195 344 195 351 185 351 185 365 179 365 -outline {} -fill \#000000 -width 0} {polygon 215 337 209 337 209 331 228 331 228 337 222 337 222 365 215 365 -outline {} -fill \#000000 -width 0} {polygon 241 331 248 331 251 355 254 331 260 331 263 355 266 331 272 331 267 365 260 365 257 341 254 365 247 365 -outline {} -fill \#000000 -width 0} {polygon 293 331 301 331 308 365 302 365 301 358 294 358 293 365 286 365 -outline {} -fill \#000000 -width 0} {polygon 297 337 295 352 299 352 -outline {} -fill $bg -width 0} {polygon 324 331 325 331 327 331 329 331 332 331 334 331 335 331 336 331 337 331 338 331 339 332 340 332 340 333 341 333 341 334 342 334 342 335 342 336 343 337 343 338 343 339 343 340 343 341 343 342 343 343 342 343 342 344 342 345 341 345 341 346 340 347 339 348 338 348 339 349 340 349 341 349 341 350 342 351 342 352 342 353 342 354 342 355 343 356 343 357 343 358 343 359 343 360 343 361 343 362 343 363 343 364 344 364 344 365 342 365 340 365 338 365 337 365 336 365 336 364 336 363 336 362 336 361 336 360 336 359 336 358 336 357 336 356 336 355 336 354 335 353 335 352 335 351 334 351 333 351 332 351 331 351 330 351 330 352 330 355 330 358 330 361 330 364 330 365 329 365 327 365 325 365 324 365 324 364 324 363 324 360 324 357 324 353 324 348 324 343 324 339 324 335 324 333 324 331 -outline {} -fill \#000000 -width 0} {polygon 330 345 331 345 332 345 333 345 334 345 335 345 335 344 335 343 336 343 336 342 336 341 336 340 336 339 335 338 335 337 334 337 333 336 332 336 331 336 330 336 330 337 330 338 330 341 330 343 330 345 -outline {} -fill $bg -width 0} {polygon 360 331 376 331 376 337 367 337 367 344 376 344 376 351 367 351 367 358 377 358 377 365 360 365 -outline {} -fill \#000000 -width 0} {polygon 416 331 423 331 423 365 416 365 -outline {} -fill \#000000 -width 0} {polygon 440 331 448 331 454 353 454 331 460 331 460 365 452 365 446 341 446 365 440 365 -outline {} -fill \#000000 -width 0} {polygon 485 343 485 342 485 341 485 340 485 339 485 338 485 337 484 337 484 336 483 336 483 335 482 335 482 336 481 336 480 337 480 338 480 339 480 340 480 341 479 341 479 343 479 344 479 346 479 347 479 348 479 349 479 351 479 352 479 353 480 354 480 355 480 356 480 357 480 358 480 359 481 359 481 360 482 360 483 360 484 360 484 359 485 359 485 358 485 357 485 356 485 355 485 354 485 353 485 352 487 352 489 352 491 352 492 352 492 353 492 354 492 356 492 357 491 357 491 358 491 359 491 360 490 361 490 362 490 363 489 363 488 364 487 364 486 365 485 365 484 366 482 366 480 365 479 365 478 365 477 365 477 364 476 364 476 363 475 362 474 361 474 360 473 358 473 357 473 356 473 355 473 353 472 352 472 350 472 349 472 348 472 347 472 346 473 344 473 343 473 342 473 341 473 339 473 338 474 336 474 335 475 334 476 333 476 332 478 331 479 330 481 330 482 330 483 330 485 330 486 330 486 331 487 331 488 332 489 332 489 333 490 333 490 334 491 335 491 336 491 337 491 338 492 340 492 341 492 342 492 343 491 343 490 343 488 343 486 343 485 343 -outline {} -fill \#000000 -width 0} {polygon 500 356 506 356 506 365 500 365 -outline {} -fill \#000000 -width 0} {polygon 132 265 133 265 134 265 136 265 137 265 138 265 139 265 140 264 141 264 142 264 143 264 143 263 144 263 145 262 146 262 146 261 146 260 147 259 148 258 148 256 148 255 148 254 148 253 148 252 148 251 148 250 148 249 148 248 147 247 147 246 146 245 145 244 144 244 143 243 142 243 141 243 140 243 138 243 137 243 135 243 135 244 135 245 134 247 134 250 134 254 133 257 133 261 133 263 133 264 132 265 -outline {} -fill $bg -width 0} } foreach obj $logo_objs { eval $c create $obj -tags logo } } #*********************************************************************** # %PROCEDURE: doLogo # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Does the logo thing #*********************************************************************** proc doLogo {} { canvas .c -width 600 -height 400 -bg #FFFFFF pack .c drawLogo .c #FFFFFF # Funky effect .c create text 4 4 -anchor nw -text "Welcome to Remind" \ -fill red -font {-family times -size -24 -weight bold} -tags remind .c lower remind .c move logo -300 20 update idletasks for {set i 0} {$i < 16} {incr i} { .c move logo 20 0 update idletasks after 30 } .c create text 4 28 -anchor nw -text "http://www.roaringpenguin.com" \ -fill red -font {-family courier -size -14 -weight bold} set rem [FindRemind] if {$rem != ""} { .c create text 4 52 -anchor nw -text "Found existing Remind... reusing settings" -fill red -font {-family courier -size -14 -weight bold} .c create text 4 66 -anchor nw -text "from $rem" -fill red -font {-family courier -size -14 -weight bold} } update idletasks after 2500 } #*********************************************************************** # %PROCEDURE: FindRemind # %ARGUMENTS: # None # %RETURNS: # Full path to an existing "remind" if one is found. Otherwise, # empty string. #*********************************************************************** proc FindRemind {} { global env set path [concat [split $env(PATH) ":"] "/bin" "/usr/bin" "/usr/local/bin"] foreach thing $path { if [file executable [file join $thing "remind"]] { return [file join $thing "remind"] } } return {} } #*********************************************************************** # %PROCEDURE: SetConfigFromRemind # %ARGUMENTS: # None # %RETURNS: # Sets config settings based on existing remind (if one found) or else # sensible defaults. #*********************************************************************** proc SetConfigFromRemind {} { global Config SetConfigDefaults set rem [FindRemind] if {"$rem" == ""} { return } set dir [file dirname $rem] set Config(INST_DIR) $dir if {"$dir" == "/usr/local/bin"} { set Config(MAN_DIR) "/usr/local/man" } elseif {$dir == "/usr/bin"} { set Config(MAN_DIR) "/usr/share/man" } # Check for existing man page if {[file readable "/usr/share/man/man1/remind.1"]} { set Config(MAN_DIR) "/usr/share/man" } elseif {[file readable "/usr/man/man1/remind.1"]} { set Config(MAN_DIR) "/usr/man" } elseif {[file readable "/usr/local/man/man1/remind.1"]} { set Config(MAN_DIR) "/usr/local/man" } # Query Remind for the rest QueryRemind $rem LAT_DEG {$LatDeg} QueryRemind $rem LAT_MIN {$LatMin} QueryRemind $rem LON_DEG {$LongDeg} QueryRemind $rem LON_MIN {$LongMin} QueryRemind $rem LOCATION {$Location} QueryRemind $rem DATESEP {$DateSep} QueryRemind $rem TIMESEP {$TimeSep} QueryRemind $rem LANGUAGE {language()} set $Config(LAT_MIN) [expr abs($Config(LAT_MIN))] if {$Config(LAT_DEG) >= 0} { set Config(NORTHERN_HEMISPHERE) 1 } else { set Config(NORTHERN_HEMISPHERE) 0 set Config(LAT_DEG) [expr abs($Config(LAT_DEG))] } set $Config(LON_MIN) [expr abs($Config(LON_MIN))] if {$Config(LON_DEG) >= 0} { set Config(WESTERN_HEMISPHERE) 1 } else { set Config(WESTERN_HEMISPHERE) 0 set Config(LON_DEG) [expr abs($Config(LON_DEG))] } # Get default page from rem2ps set rem2ps [file join $dir "rem2ps"] catch { exec $rem2ps -m help } err set errlist [split $err "\n"] set err [lindex $errlist end] if {[string match "Default media type is*" $err]} { set Config(DEFAULT_PAGE) [lindex $err end] } } proc QueryRemind { rem symbol rem_msg } { global Config catch { set fp [open "| $rem -" "r+"] puts $fp "banner %\nMSG \[$rem_msg\]%\nFLUSH\n" flush $fp gets $fp line catch { close $fp } } if {"$line" == ""} { return } set Config($symbol) $line } CheckSanity CreateMainDialog remind-03.01.15/configure0000755000076400007640000045224312555504043013265 0ustar dfsdfs#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="src/queue.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_list= ac_subst_vars='LTLIBOBJS LIBOBJS VERSION EGREP GREP CPP SET_MAKE LN_S INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 &5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_list " utime.h" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat <<'EOF' ********************** * * * Configuring REMIND * * * ********************** EOF ac_config_headers="$ac_config_headers src/config.h" if test "`uname -s`" = "Darwin" ; then trap 'echo Be patient...' INT TERM cat <<'EOF' Please don't use Apple products. This script will continue in 30 seconds if you insist on compiling Remind on Mac OS X. EOF for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do sleep 1 done trap - INT trap - TERM fi if uname -s | grep -i -q 'cygwin' ; then trap 'echo Be patient...' INT TERM cat <<'EOF' Please don't use Microsoft products. This script will continue in 30 seconds if you insist on compiling Remind on Cygwin. EOF for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do sleep 1 done trap - INT trap - TERM fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 $as_echo_n "checking for sqrt in -lm... " >&6; } if ${ac_cv_lib_m_sqrt+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sqrt (); int main () { return sqrt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_sqrt=yes else ac_cv_lib_m_sqrt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5 $as_echo "$ac_cv_lib_m_sqrt" >&6; } if test "x$ac_cv_lib_m_sqrt" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned short" >&5 $as_echo_n "checking size of unsigned short... " >&6; } if ${ac_cv_sizeof_unsigned_short+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned short))" "ac_cv_sizeof_unsigned_short" "$ac_includes_default"; then : else if test "$ac_cv_type_unsigned_short" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (unsigned short) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_unsigned_short=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_short" >&5 $as_echo "$ac_cv_sizeof_unsigned_short" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned int" >&5 $as_echo_n "checking size of unsigned int... " >&6; } if ${ac_cv_sizeof_unsigned_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned int))" "ac_cv_sizeof_unsigned_int" "$ac_includes_default"; then : else if test "$ac_cv_type_unsigned_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (unsigned int) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_unsigned_int=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_int" >&5 $as_echo "$ac_cv_sizeof_unsigned_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5 $as_echo_n "checking size of unsigned long... " >&6; } if ${ac_cv_sizeof_unsigned_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then : else if test "$ac_cv_type_unsigned_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (unsigned long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_unsigned_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5 $as_echo "$ac_cv_sizeof_unsigned_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long _ACEOF for ac_header in sys/file.h glob.h wctype.h locale.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi for ac_header in $ac_header_list do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5 $as_echo_n "checking whether utime accepts a null argument... " >&6; } if ${ac_cv_func_utime_null+:} false; then : $as_echo_n "(cached) " >&6 else rm -f conftest.data; >conftest.data # Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. if test "$cross_compiling" = yes; then : ac_cv_func_utime_null='guessing yes' else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_UTIME_H # include #endif int main () { struct stat s, t; return ! (stat ("conftest.data", &s) == 0 && utime ("conftest.data", 0) == 0 && stat ("conftest.data", &t) == 0 && t.st_mtime >= s.st_mtime && t.st_mtime - s.st_mtime < 120); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_utime_null=yes else ac_cv_func_utime_null=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_utime_null" >&5 $as_echo "$ac_cv_func_utime_null" >&6; } if test "x$ac_cv_func_utime_null" != xno; then ac_cv_func_utime_null=yes $as_echo "#define HAVE_UTIME_NULL 1" >>confdefs.h fi rm -f conftest.data { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi if test "$GCC" = yes; then CFLAGS="$CFLAGS -Wall -Wstrict-prototypes" fi for ac_func in setenv unsetenv glob mbstowcs setlocale do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done VERSION=03.01.15 ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "www/Makefile") CONFIG_FILES="$CONFIG_FILES www/Makefile" ;; "src/version.h") CONFIG_FILES="$CONFIG_FILES src/version.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi remind-03.01.15/configure.in0000644000076400007640000000326112555504027013661 0ustar dfsdfsdnl Process this file with autoconf to produce a configure script. AC_INIT(src/queue.c) cat <<'EOF' ********************** * * * Configuring REMIND * * * ********************** EOF AC_CONFIG_HEADER(src/config.h) if test "`uname -s`" = "Darwin" ; then trap 'echo Be patient...' INT TERM cat <<'EOF' Please don't use Apple products. This script will continue in 30 seconds if you insist on compiling Remind on Mac OS X. EOF for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do sleep 1 done trap - INT trap - TERM fi if uname -s | grep -i -q 'cygwin' ; then trap 'echo Be patient...' INT TERM cat <<'EOF' Please don't use Microsoft products. This script will continue in 30 seconds if you insist on compiling Remind on Cygwin. EOF for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do sleep 1 done trap - INT trap - TERM fi dnl Checks for programs. AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET dnl Checks for libraries. dnl Replace `main' with a function in -lm: AC_CHECK_LIB(m, sqrt) dnl Integer sizes AC_CHECK_SIZEOF(unsigned short) AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(unsigned long) dnl Checks for header files. AC_CHECK_HEADERS(sys/file.h glob.h wctype.h locale.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_STRUCT_TM dnl Checks for library functions. AC_FUNC_UTIME_NULL AC_HEADER_TIME if test "$GCC" = yes; then CFLAGS="$CFLAGS -Wall -Wstrict-prototypes" fi AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale) VERSION=03.01.15 AC_SUBST(VERSION) AC_OUTPUT(src/Makefile www/Makefile src/version.h) remind-03.01.15/contrib/README0000644000076400007640000000052212514120337013656 0ustar dfsdfsThis directory contains contributed scripts. They are provided "as-is" with no warranty. Please do not contact Dianne Skoll or Roaring Penguin Software Inc. for help with these scripts; instead, contact the script authors. You should check the upstream sources; there may be newer versions of these scripts available. -- Dianne Skoll remind-03.01.15/contrib/ical2rem.pl0000755000076400007640000002223411274072771015052 0ustar dfsdfs#!/usr/bin/perl -w # # ical2rem.pl - # Reads iCal files and outputs remind-compatible files. Tested ONLY with # calendar files created by Mozilla Calendar/Sunbird. Use at your own risk. # Copyright (c) 2005, 2007, Justin B. Alcorn # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # # version 0.5.2 2007-03-23 # - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME # - remove project-lead-time, since Category was a non-standard attribute # - NOTE: There is a bug in iCal::Parser v1.14 that causes multiple calendars to # fail if a calendar with recurring events is followed by a calendar with no # recurring events. This has been reported to the iCal::Parser author. # version 0.5.1 2007-03-21 # - BUG: Handle multiple calendars on STDIN # - add --heading option for priority on section headers # version 0.5 2007-03-21 # - Add more help options # - --project-lead-time option # - Supress printing of heading if there are no todos to print # version 0.4 # - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg # - Change to GetOptions # - Change to pipe # - Add --label, --help options # - Add Help Text # - Change to subroutines # - Efficiency and Cleanup # version 0.3 # - Convert to GPL (Thanks to Mark Stosberg) # - Add usage # version 0.2 # - add command line switches # - add debug code # - add SCHED _sfun keyword # - fix typos # version 0.1 - ALPHA CODE. =head1 SYNOPSIS cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem All options have reasonable defaults: --label Calendar name (Default: Calendar) --lead-time Advance days to start reminders (Default: 3) --todos, --no-todos Process Todos? (Default: Yes) --heading Define a priority for static entries --help Usage --man Complete man page Expects an ICAL stream on STDIN. Converts it to the format used by the C script and prints it to STDOUT. =head2 --label ical2rem.pl --label "Bob's Calendar" The syntax generated includes a label for the calendar parsed. By default this is "Calendar". You can customize this with the "--label" option. =head2 --lead-time ical2rem.pl --lead-time 3 How may days in advance to start getting reminders about the events. Defaults to 3. =head2 --no-todos ical2rem.pl --no-todos If you don't care about the ToDos the calendar, this will surpress printing of the ToDo heading, as well as skipping ToDo processing. =head2 --heading ical2rem.pl --heading "PRIORITY 9999" Set an option on static messages output. Using priorities can made the static messages look different from the calendar entries. See the file defs.rem from the remind distribution for more information. =cut use strict; use iCal::Parser; use DateTime; use Getopt::Long 2.24 qw':config auto_help'; use Pod::Usage; use Data::Dumper; use vars '$VERSION'; $VERSION = "0.5.2"; # Declare how many days in advance to remind my $DEFAULT_LEAD_TIME = 3; my $PROCESS_TODOS = 1; my $HEADING = ""; my $help; my $man; my $label = 'Calendar'; GetOptions ( "label=s" => \$label, "lead-time=i" => \$DEFAULT_LEAD_TIME, "todos!" => \$PROCESS_TODOS, "heading=s" => \$HEADING, "help|?" => \$help, "man" => \$man ); pod2usage(1) if $help; pod2usage(-verbose => 2) if $man; my $month = ['None','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; my @calendars; my $in; while (<>) { $in .= $_; if (/END:VCALENDAR/) { push(@calendars,$in); $in = ""; } } my $parser = iCal::Parser->new(); my $hash = $parser->parse_strings(@calendars); ############################################################## # # Subroutines # ############################################################# # # _process_todos() # expects 'todos' hashref from iCal::Parser is input # returns String to output sub _process_todos { my $todos = shift; my ($todo, @newtodos, $leadtime); my $output = ""; $output .= 'REM '.$HEADING.' MSG '.$label.' ToDos:%"%"%'."\n"; # For sorting, make sure everything's got something # To sort on. my $now = DateTime->now; for $todo (@{$todos}) { # remove completed items if ($todo->{'STATUS'} && $todo->{'STATUS'} eq 'COMPLETED') { next; } elsif ($todo->{'DUE'}) { # All we need is a due date, everything else is sugar $todo->{'SORT'} = $todo->{'DUE'}->clone; } elsif ($todo->{'DTSTART'}) { # for sorting, sort on start date if there's no due date $todo->{'SORT'} = $todo->{'DTSTART'}->clone; } else { # if there's no due or start date, just make it now. $todo->{'SORT'} = $now; } push(@newtodos,$todo); } if (! (scalar @newtodos)) { return ""; } # Now sort on the new Due dates and print them out. for $todo (sort { DateTime->compare($a->{'SORT'}, $b->{'SORT'}) } @newtodos) { my $due = $todo->{'SORT'}->clone(); my $priority = ""; if (defined($todo->{'PRIORITY'})) { if ($todo->{'PRIORITY'} == 1) { $priority = "PRIORITY 1000"; } elsif ($todo->{'PRIORITY'} == 3) { $priority = "PRIORITY 7500"; } } if (defined($todo->{'DTSTART'}) && defined($todo->{'DUE'})) { # Lead time is duration of task + lead time my $diff = ($todo->{'DUE'}->delta_days($todo->{'DTSTART'})->days())+$DEFAULT_LEAD_TIME; $leadtime = "+".$diff; } else { $leadtime = "+".$DEFAULT_LEAD_TIME; } $output .= "REM ".$due->month_abbr." ".$due->day." ".$due->year." $leadtime $priority MSG \%a $todo->{'SUMMARY'}\%\"\%\"\%\n"; } $output .= 'REM '.$HEADING.' MSG %"%"%'."\n"; return $output; } ####################################################################### # # Main Program # ###################################################################### print _process_todos($hash->{'todos'}) if $PROCESS_TODOS; my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid); print 'REM '.$HEADING.' MSG '.$label.' Events:%"%"%'."\n"; my $events = $hash->{'events'}; foreach $yearkey (sort keys %{$events} ) { my $yearevents = $events->{$yearkey}; foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){ my $monevents = $yearevents->{$monkey}; foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) { my $dayevents = $monevents->{$daykey}; foreach $uid (sort { DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'}) } keys %{$dayevents}) { my $event = $dayevents->{$uid}; if ($eventsbyuid{$uid}) { my $curreventday = $event->{'DTSTART'}->clone; $curreventday->truncate( to => 'day' ); $eventsbyuid{$uid}{$curreventday->epoch()} =1; for (my $i = 0;$i < $DEFAULT_LEAD_TIME && !defined($event->{'LEADTIME'});$i++) { if ($eventsbyuid{$uid}{$curreventday->subtract( days => $i+1 )->epoch() }) { $event->{'LEADTIME'} = $i; } } } else { $eventsbyuid{$uid} = $event; my $curreventday = $event->{'DTSTART'}->clone; $curreventday->truncate( to => 'day' ); $eventsbyuid{$uid}{$curreventday->epoch()} =1; } } } } } foreach $yearkey (sort keys %{$events} ) { my $yearevents = $events->{$yearkey}; foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){ my $monevents = $yearevents->{$monkey}; foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) { my $dayevents = $monevents->{$daykey}; foreach $uid (sort { DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'}) } keys %{$dayevents}) { my $event = $dayevents->{$uid}; if (exists($event->{'LEADTIME'})) { $leadtime = "+".$event->{'LEADTIME'}; } else { $leadtime = "+".$DEFAULT_LEAD_TIME; } my $start = $event->{'DTSTART'}; print "REM ".$start->month_abbr." ".$start->day." ".$start->year." $leadtime "; if ($start->hour > 0) { print " AT "; print $start->strftime("%H:%M"); print " SCHED _sfun MSG %a %2 "; } else { print " MSG %a "; } print "%\"$event->{'SUMMARY'}"; print " at $event->{'LOCATION'}" if $event->{'LOCATION'}; print "\%\"%\n"; } } } } exit 0; #:vim set ft=perl ts=4 sts=4 expandtab : remind-03.01.15/contrib/rem2ics-0.93/Makefile0000644000076400007640000000042711274072771016407 0ustar dfsdfsDESTDIR?= PREFIX?=/usr BINDIR?=$(PREFIX)/bin MANDIR?=$(PREFIX)/share/man default: rem2ics.1 rem2ics.1: pod2man -c "" rem2ics > rem2ics.1 install: rem2ics.1 install -p -D rem2ics $(DESTDIR)$(BINDIR)/rem2ics install -p -D -m 0644 rem2ics.1 $(DESTDIR)$(MANDIR)/man1/rem2ics.1 remind-03.01.15/contrib/rem2ics-0.93/rem2ics0000755000076400007640000010044012514121377016230 0ustar dfsdfs#!/usr/bin/perl -w # rem2ics -- convert the output of "remind -s" into RFC2445 iCalendar format. # Copyright 2007,2008,2009 # Mark Atwood # Paul Hinze # Michael Schultz # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc. # 51 Franklin Street, Fifth Floor # Boston MA 02110-1301 USA use strict; use warnings; =head1 NAME rem2ics - convert the output of "remind -s" into RFC2445 iCalendar format. =head1 SYNOPSIS TZ=I B [B<-man>] [B<-do>] [B<-norecur>] [B<-usetag>] Einput Eoutput =head1 OPTIONS AND ARGUMENTS =over 8 =item B<-man> Print the manual page and exit. =item B<-do> Actually do the conversion. Otherwise just print a brief help message and usage example, and then exit. =item B<-norecur> Do not attempt to detect and fold together recurring events. =item B<-usetag> Generate UIDs using remind TAG clauses. =back Input is from standard input Output is to standard output. =head1 USAGE remind -s360 -irem2ics=1 ~/.reminders 1 Jan 1991 | TZ=PST8PDT rem2ics -do >reminders.ics This tells B to use ~/.reminders, and to process the entire range of dates it can handle (from Jan 1 1991 to Dec 31 2020), and to define a variable named C, which can be used in C / C pairs. B will use a timezone of PST8PDT, and will fold events that have the same name and duration into a single iCalendar VEVENT object. =head1 NOTES =head2 Timezones and the TZ environment variable. B uses the TZ environment variable to determine the value of the RFC2445 TZID property. If you are running on a Linux or other GNU libc based system, you probably don't (and probably shouldn't) normally have TZ set. You can confirm this by running C at a shell prompt. If your remind data is in your "local time", and it probably is, you should probably set TZ to a good name for your local timezone just for the run of this script. You probably should NOT set TZ in your login scripts. You can use TZ like this: remind -s ~/.reminders | TZ=PST8PDT rem2ics -do >reminders.ics or remind -s ~/.reminders | TZ=US/Pacific rem2ics -do >reminders.ics If, for some reason, your remind files are all in GMT instead of localtime (you smart person you!), you can do this: remind -s ~/.reminders | TZ=GMT rem2ics -do >reminders.ics or remind -s ~/.reminders | TZ=0 rem2ics -do >reminders.ics and B will use the ISO8601 "Z" notation for GMT time in the ics file. (Other synonyms for GMT are the empty string (not the same as the TZ not set), "I<0>", "I", "I", "I", "I", "I, and "I".) If you leave TZ undefined and unset, B will use the ISO8601 "T" notation date strings with no TZID property, which RFC2445 calls a "floating time". Who knows, it might work for you! The TZ string value is literally incorporated into the iCalendar stream, so whatever your iCalendar-using application needs is what you should use. You may have to experiment a bit. You can look around in C to get the names of every timezone anywhere. This is the "Olson database" that RFC2445 refers to. Read the man page for L for more than you ever wanted to know about the format of these files, and about GNU libc's handling of timezones. As complex as it is, it's certainly better than what POSIX defines or what most legacy UNIX systems do, and most certainly better than Microsoft, who in their "cutting edge" "state of the art" "server" OS, still hasn't figured out that daylight time rules might be different in different years. If you just ran B without reading all this stuff, or if you don't want to worry about it at all, and somehow your iCalendar application manager is able to guess the proper timezone for you, just leave TZ undefined, and B will use the ISO8601 "T" notation date strings with no TZID property, which RFC2445 calls a "floating time". Who knows, it might work for you! =head2 Detecting recurring events B tries to detect recurring events. If any multiple events appear with exactly the text and exactly the same duration (including "no duration"), instead of multiple VEVENT objects, there will be just one VEVENT object, that will have a RFC2445 C property. B is not yet smart enough to derive an C based recurrance. If you really want that feature, either implement it and send in a patch, or contact the author and convince him to do it. =head2 Other iCalendar Properties B does not generate C or C. One would have to heuristically parse them out of the text, and everyone uses a idiosyncratic way of putting things in B. If the B<-usetag> option is not used or no C is set for a reminder, B will synthesize C properties for each VEVENT, but the UIDs will be different (and unique) for each run of B. If you run rem2ics twice and import the two resulting ICS streams into your new scheduling program, your appointments will appear twice. If, however, you have set C clauses in your reminders and activated B<-usetag>, these will be used. The same applies for tags synthesized by B's B<-y> option. Hence, it is more useful to use the B<-y> option than to let B synthesize UIDs, because the UIDs will stay the same across multiple runs. =head2 Other iCalendar Perl objects Why does't B use any of the iCalendar Perl stuff in CPAN? Because I don't trust them, and they are too big for this app. One links to a binary library. Another hasn't been maintained since 1991, and is full of notes as to how buggy and incomplete it is. And so forth. I am not at this moment interested in groveling around in L, L, L, L, or C. =head2 Previous implementation There is a working quick & dirty rem2ics written in awk by Anthony J. Chivetta Eachivetta@gmail.comE. But it has the following problems: it doesn't escape the text, it doesn't handle events that cross over midnight, it doesn't do timezones, it doesn't enforce the correct EOL sequence, and it doesn't fold long lines. This is a replacement for that script. =head1 TODO If TZ not set, grab out of system config somewhere Detect recurring events. If I'm REALLY smart, derive RRULE Handle characters not in US-ASCII. Latin1? UTF8? =head1 VERSION HISTORY =over 8 =item version 0.1 2007-02-08 First cut. =item version 0.2 2007-02-09 Reorg into multipass over a data structure. =item version 0.3 2007-02-10 Collapse repeating events. Fold output lines. =item version 0.9 2007-02-11 POD. Command line options. First public release. =item version 0.91 2007-02-14 Bug fix, error message for non-recurring events =item version 0.92 2008-01-28 Bug fix, rem2ics 0.91 chokes on timed reminders with duration using `remind -s` as it functions in remind-03.01.03. Remind 3.01 changed how the -s data is formated for events that have a duration Patch by Paul Hinze Epaul dot t dot hinze at gmail dot comE and Michael Schultz Emjschultz at gmail dot comE =item version 0.93 2009-06-25 Add B<-usetag> option to allow for UIDs to stay the same across multiple runs by using the remind TAG clause. Patch by Tim Weber Escy at scytale dot nameE =back =head1 SEE ALSO L L L L L =head1 AUTHOR Copyright 2007,2008,2009 by Mark Atwood Eme+rem2ics@mark.atwood.nameE. L. Please report bugs (with patches, if possible). Inspired by Anthony J. Chivetta Eachivetta@gmail.comE's rem2ics in awk. Thank you to Dianne Skoll Edfs@roaringpengiun.com for Remind, and to the IETF calsch wg for the iCalendar specification. =cut use Getopt::Long; use Pod::Usage; my $app_name = "rem2ics"; my $app_version = "0.93"; # process the command line my %options; GetOptions(\%options, qw(man do norecurr usetag)) || pod2usage(2); pod2usage(-verbose => 2) if ($options{man}); unless ($options{do}) { print STDERR "Run \"$0 -man\" for information and usage examples.\n" . "Pay special attention to information about timezone.\n"; exit(99); } # grab the hostname # this is used as part of the UID property of each VEVENT my $ical_uid_hostname = $ENV{'HOSTNAME'}; unless ($ical_uid_hostname) { print STDERR "Warning! " . "The environment variable HOSTNAME was not properly set.\n" . "Will use \"localhost\" in the RFC2445 UID property\n"; $ical_uid_hostname = "localhost"; } # look for the TZ my $ical_tzid = undef; if (exists $ENV{'TZ'}) { $ical_tzid = $ENV{'TZ'}; my %synonyms_for_gmt = ( '' => 1, '0' => 1, 'z' => 1, 'zulu' => 1, 'greenwitch' => 1, 'gmt' => 1, 'gmt+0' => 1, 'gmt-0' => 1, ); if (exists $synonyms_for_gmt{lc($ical_tzid)}) { $ical_tzid = ''; # empty means GMT, below } } else { # leave it undefined, that has a meaning below } # RFC2445 DTSTAMP property will be the time we started running ($^T) my ($ical_dtstamp); { my @gt = gmtime($^T); $ical_dtstamp = sprintf("%04d%02d%02dZ%02d%02d%02dZ", 1900+$gt[5], $gt[4]+1, $gt[3], $gt[2], $gt[1], $gt[0]); } my ($cnt, $v, @events); $cnt = 0; foreach () { $cnt++; s/#.*//; # toss comments next if /^\s*$/; # skip blank lines chomp; $v = undef; # store the raw line $v->{src} = $_; $v->{cnt} = $cnt; # split and parse the line # if we don't like it, skip it and go around again # sf[0] = date, in yyyy/mm/dd format # sf[1] = special, usually "*" # sf[2] = tag, usually "*" # sf[3] = duration, in minutes # sf[4] = time, since midnight, in minutes # sf[5] = text my @sf = split(' ', $_, 6); next unless ($sf[1] eq '*'); # ignore SPECIAL lines next unless (($sf[3] eq '*') or ($sf[3] =~ m/\d+/)); next unless (($sf[4] eq '*') or ($sf[4] =~ m/\d+/)); next unless (length($sf[5]) > 0); my @dt = split('/', $sf[0], 3); next unless ($dt[0] =~ m/^\d{4}$/); # year next unless ($dt[1] =~ m/^\d{2}$/); # month next unless ($dt[2] =~ m/^\d{2}$/); # day if ($sf[4] ne "*") { # a time was given # When an event has a time, remind -s "helpfully" also # puts it as text at the start of the text portion. # This takes the following form: # ##:##[a|p]m # or, if the event has a duration: # ##:##[a|p]m-##:##[a|p]m # Rather than a nasty regex, just splitting at the # first space does the trick. my($extra_time, $textmsg) = split(' ', $sf[5], 2); $sf[5] = $textmsg; } $v->{sf} = \@sf; $v->{dt} = \@dt; push @events, $v; } # generate the "date time string" for each event foreach $v (@events) { if (${$v->{sf}}[4] eq "*") { # no time was given $v->{dts} = sprintf("%04d%02d%02d", @{$v->{dt}}); } else { # a time was given my ($t_hr, $t_mn) = &idiv(${$v->{sf}}[4], 60); $v->{dts} = sprintf("%04d%02d%02dT%02d%02d00", @{$v->{dt}}, $t_hr, $t_mn); } } my(%grovel); # if the user doesnt want recurrance detection unless ($options{norecurr}) { # then dont put events in the grovel hash foreach $v (@events) { # key is duration followed by text # \036 is "ASCII RS Record Separator" my $k = ${$v->{sf}}[3] . "\036" . ${$v->{sf}}[5]; push @{$grovel{$k}}, $v; } foreach my $k (keys %grovel) { if ((scalar @{$grovel{$k}}) > 1) { $v = ${$grovel{$k}}[0]; $v->{recurlist} = \@{$grovel{$k}}; foreach my $v0 (@{$grovel{$k}}) { $v0->{is_recurrance} = $v; } } } } # All of the individual events are in the @events array. All of the # unique combinations of duration/event name are the keys in the # %grovel hash, the elements of which are references to an arrays of # references to the events, in the same ordering as they we read by # us, which *ought* to be in datewise order. I don't know if "remind # -s" actually sorts into true chronological order. If it doesn't, we # might have a problem if a recurring event has two instances both on # the first day. # Every event that is recurring has a "is_recurrance" property. # Additionally, (hopefully) the first/earliest event in a set of # recurrances has a "recurlist" property. The "recurlist" is a # reference to a list of references to each of the events. The first # one on that list will be the same event that has the "recurlist" # property. The "is_recurrance" property is a reference back to the # event that has the "recurlist" property. foreach my $k (keys %grovel) { next if ((scalar @{$grovel{$k}}) <= 1); my $recur_str = ""; foreach $v (@{$grovel{$k}}) { if (${$v->{sf}}[4] eq "*") { # no time was given $recur_str .= ($v->{dts} . ","); } else { if (defined($ical_tzid)) { if ($ical_tzid eq '') { # tz is defined but empty, so in GMT $recur_str .= $v->{dts} . "Z,"; } else { # tz is non-zero, so output the tz as well $recur_str .= $v->{dts} . ","; } } else { # undefined tz, just floating time $recur_str .= $v->{dts} . ","; } } } # the recur_str now has an extra comma at the end. chop it off chop($recur_str); ${$grovel{$k}}[0]->{recur_str} = $recur_str; } foreach my $k (keys %grovel) { next if ((scalar @{$grovel{$k}}) <= 1); my $v = ${$grovel{$k}}[0]; # grab the head of each list if (${$v->{sf}}[4] eq "*") { # no time was given # the default value type for an RDATE is DATE-TIME, # we much change the type to DATE $v->{i_rdate} = sprintf("RDATE;VALUE=DATE:"); } else { if (defined($ical_tzid)) { if ($ical_tzid eq '') { # tz is defined but empty, so in GMT $v->{i_rdate} = sprintf("RDATE:"); } else { # tz is non-zero, so output the tz as well $v->{i_rdate} = sprintf("RDATE;TZID=%s:", $ical_tzid); } } else { # undefined tz, just floating time $v->{i_rdate} = sprintf("RDATE:"); } } # now stick the recur_str onto the end $v->{i_rdate} .= $v->{recur_str}; # if we ever get memory tight, we can probably undef($v->{recur_str}) } foreach $v (@events) { # for recurrant events, skip those that arnt the "head" next if ($v->{is_recurrance} and (not $v->{recurlist})); if (${$v->{sf}}[4] eq "*") { # no time was given $v->{i_dtstart} = sprintf("DTSTART:%s", $v->{dts}); } else { if (defined($ical_tzid)) { if ($ical_tzid eq '') { # tz is defined but empty, so in GMT $v->{i_dtstart} = sprintf("DTSTART:%sZ", $v->{dts}); } else { # tz is non-zero, so output the tz as well $v->{i_dtstart} = sprintf("DTSTART;TZID=%s:%s", $ical_tzid, $v->{dts}); } } else { # undefined tz, just floating time $v->{i_dtstart} = sprintf("DTSTART:%s", $v->{dts}); } } if (${$v->{sf}}[3] ne "*") { # a duration was given # It's convienient that RFC2445 defines DURATION, thus we # don't need to calculate DTEND, with awkward figuring out # crossing hours, days, months, year, etc. Instead we # will let the iCalendar consuming application worry about it. $v->{i_duration} = sprintf("PT%dM", ${$v->{sf}}[3]); } } # output header print "BEGIN:VCALENDAR\015\012" . "VERSION:2.0\015\012" . "PRODID:http://mark.atwood.name/code/rem2ics" . " $app_name $app_version\015\012"; # output each vevent foreach $v (@events) { # for recurrant events, only output the "head", skip the others next if ($v->{is_recurrance} and (not $v->{recurlist})); print "BEGIN:VEVENT\015\012"; my $tag = ${$v->{sf}}[2]; # if $tag is not set, fake up a UID from start time, process id & input line count if ($tag eq "*" || !$options{usetag}) { $tag = sprintf("%x.%x.%x", $^T, $$, $v->{cnt}); } # add rem2ics and hostname to UID print &lineify(sprintf("UID:rem2ics.%s@%s", $tag, $ical_uid_hostname)); print &lineify("SUMMARY:" . "ify(${$v->{sf}}[5])); print &lineify($v->{i_dtstart}); print &lineify("DURATION:" . $v->{i_duration}) if ($v->{i_duration}); print &lineify($v->{i_rdate}) if ($v->{i_rdate}); print &lineify("DTSTAMP:" . $ical_dtstamp); print &lineify("COMMENT: generated by $app_name $app_version\\n" . " http://mark.atwood.name/code/rem2ics\\n" . " data[" . $v->{cnt} . "]=|" . "ify($v->{src}) . "|"); print "END:VEVENT\015\012"; } # output trailer print "END:VCALENDAR\015\012"; # integer division, return both quotient and remainder sub idiv { my $n = shift; my $d = shift; my $r = $n; my $q = 0; while ($r >= $d) { $r = $r - $d; $q = $q + 1; } return ($q, $r); } # todo, perl5 version that defines ()*, need to specify a requires up top sub lineify { return join("\015\012 ", unpack('(A72)*', shift)) . "\015\012"; } sub quotify { my $s = shift; return $s if $s =~ m/^(\w| )*$/; $s =~ s/\\/\\\\/gso; $s =~ s/\n/\\n/gso; $s =~ s/\s/ /gso; $s =~ s/\"/\\"/gso; $s =~ s/\,/\\,/gso; $s =~ s/\:/\\:/gso; $s =~ s/\;/\\;/gso; return $s; } __END__ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS EOF remind-03.01.15/contrib/rem2ics-0.93/rem2ics.spec0000644000076400007640000000202111274072771017157 0ustar dfsdfsName: rem2ics Version: 0.93 Release: 1%{?dist} Summary: Converts the output of "remind -s" into RFC2445 iCalendar format Group: Applications/Productivity License: GPLv2+ URL: http://mark.atwood.name/code/rem2ics/ Source0: http://mark.atwood.name/code/rem2ics/rem2ics-%{version}.tar.gz Source1: rem2ics-Makefile BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch BuildRequires: perl %description rem2ics converts the output of "remind -s" into RFC2445 iCalendar format. You may want to install remind if you install this package. %prep %setup -q -c cp -a %SOURCE1 Makefile %build make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT mkdir $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) %doc %{_bindir}/rem2ics %{_mandir}/man1/rem2ics.1* %changelog * Tue Mar 25 2008 Till Maas - 0.92-1 - initial spec for Fedora remind-03.01.15/contrib/remind-conf-mode.06/ac-remind.el0000644000076400007640000000320411274073602020532 0ustar dfsdfs;;; setup for remind autocompletion (totally optional) ;; put something like ;; (add-hook 'remind-conf-mode '(load-library "ac-remind")) in your .emacs file. (require 'auto-complete) (define-key ac-complete-mode-map "\r" nil) (defvar ac-remind-keywords '((candidates . (lambda () (all-completions ac-target remind-keywords )))) "Source for remind-conf completion keywords.") (defvar ac-remind-time-words '((candidates . (lambda () (all-completions ac-target remind-time-words)))) "Source for remind-conf time words completions.") (defvar ac-remind-builtin-variables '((candidates . (lambda () (all-completions ac-target remind-builtin-variables)))) "Source for remind-conf builtin variables.") (defvar ac-remind-type-keywords '((candidates . (lambda () (all-completions ac-target remind-type-keywords)))) "Source for remind-conf type keywords.") (defvar ac-remind-builtin-functions '((candidates . (lambda () (all-completions ac-target remind-builtin-functions)))) "Source for remind-conf completion builtin functions.") (add-hook 'remind-conf-mode-hook (lambda () "Makes auto-completion work in remind-conf-mode" (make-local-variable 'ac-sources) (setq ac-sources '(ac-remind-keywords ac-remind-builtin-variables ac-remind-builtin-functions ac-remind-type-keywords ac-remind-time-words ac-source-abbrev)) (auto-complete-mode 1))) (provide 'ac-remind) ;; (define-skeleton ac-look ;; "" ;; (skeleton-read "well? ") ;; "(when (looking-at (regexp-opt remind-" str " 'words))" \n ;; >"(setq ac-sources '(ac-remind-" str ")))" ;; )remind-03.01.15/contrib/remind-conf-mode.06/remind-conf-mode.el0000644000076400007640000004076412514120337022026 0ustar dfsdfs;;; remind-conf-mode.el --- A mode to help configure remind. ;; Copyright (C) 2008 Shelagh Manton ;; Author: Shelagh Manton with help from ;; Dianne Skoll ;; Keywords: remind configure mode ;; Version: .04 ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License ;; as published by the Free Software Foundation; either version 2 ;; of the License, or (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ;; 02111-1307, USA. ;;; Commentary: ;; Use this mode to help with the configuration of remind configuration files. ;; Put (require 'remind-conf-mode) in your .emacs file ;; or (autoload 'remind-conf-mode "remind-conf-mode" "Mode to help with remind files" t) ;; also put (add-to-list 'auto-mode-alist '("\\.rem\\'" . remind-conf-mode)) and ;; (setq auto-mode-alist ;; (cons '(".reminders$" . remind-conf-mode) auto-mode-alist)) ;; if you want to have the mode work automatically when you open a remind configuration file. ;; If you want to use the auto-complete stuff, you will need to download and install the ;; auto-complete library from http://www.cx4a.org/pub/auto-complete.el and put ;; (require 'auto-complete) in your emacs with ;; (add-hook 'remind-conf-mode-hook ;; (lambda () ;; (make-local-variable 'ac-sources) ;; (setq ac-sources '(ac-remind-conf ac-remind-builtin-variables ac-remind-builtin-functions)) ;; (auto-complete t))) ;; in your .emacs file ;; PS. you could add ac-source-abbrev ac-source-words-in-buffer to have abbrevs and ;; other words in buffer auto-complete too ;;; History: ;; Thu, Feb 14, 2008 ;; Based mode on wpld-mode tutorial and sample-mode on emacs wiki. ;; Ideas from mupad.el for font-lock styles. ;; Mon, Jan 26, 2008 ;; Added rem-setup-colors to make it easy for colourised remind output. ;; Added a demo skeleton for people to copy for easy entry of coloured remind entries. ;; tried to hook in the auto-complete library so that all known functions and keywords can be easily entered. ;; EXPERIMENTAL, but seems to work well here (emacs cvs). ;; Seems to work without case folding which is nice. wonder why it didn't yesterday? ;;; Code: (require 'font-lock); this goes in the define-derived-mode part. (when (featurep 'xemacs) (require 'overlay)) ;I wonder if this will help with font-lock and xemacs? (defgroup remind-conf nil "Options for remind-conf-mode." :group 'remind-conf :prefix "remind-conf-") (defvar remind-conf-mode-hook nil "Hook to run in `remind-conf-mode'.") ;; keymap (defvar remind-conf-mode-map (let ((remind-conf-mode-map (make-sparse-keymap))) remind-conf-mode-map) "Keymap for `remind-conf-mode'.") (define-key remind-conf-mode-map "\C-cr" 'rem-skel) (define-key remind-conf-mode-map "\C-ct" 'rem-today) (define-key remind-conf-mode-map "\C-cd" 'rem-today-skel) (define-key remind-conf-mode-map "\C-cw" 'rem-week-away) (define-key remind-conf-mode-map "\C-cx" 'rem-tomorrow) (define-key remind-conf-mode-map "\C-ca" 'rem-days-away) (define-key remind-conf-mode-map "\M-j" 'remind-indent-line) (define-key remind-conf-mode-map (kbd "RET") 'remind-indent-line) (define-key remind-conf-mode-map "\C-c\C-c" 'rem-save-file) ;; syntax-table (defvar remind-conf-syntax-table (let ((remind-conf-syntax-table (make-syntax-table text-mode-syntax-table))) (modify-syntax-entry ?\; ". 1b" remind-conf-syntax-table) (modify-syntax-entry ?\# ". 1b" remind-conf-syntax-table) (modify-syntax-entry ?\n "> b" remind-conf-syntax-table) ;Names with _ are still one word. (modify-syntax-entry ?_ "w" remind-conf-syntax-table) (modify-syntax-entry ?. "w" remind-conf-syntax-table) remind-conf-syntax-table) "Syntax table for `remind-conf-mode'.") ;;; keyword sets (defconst remind-keywords (sort (list "RUN" "REM" "ONCE" "SATISFY" "BEFORE" "UNSET" "OMIT" "OMIT" "DATE" "SKIP" "ONCE" "AFTER" "WARN" "PRIORITY" "AT" "SCHED" "IF" "ELSE" "ENDIF" "WARN" "UNTIL" "THROUGH" "SCANFROM" "DURATION" "TAG" "MSG" "MSF" "CAL" "SPECIAL" "IFTRIG" "PS" "PSFILE" "BANNER" "INCLUDE" "PUSH-OMIT-CONTEXT" "DEBUG" "DUMPVARS" "CLEAR-OMIT-CONTEXT" "POP-OMIT-CONTEXT" "SET" "ERRMSG" "FSET" "EXIT" "FLUSH" "PRESERVE" "MOON" "COLOR" "COLOUR") #'(lambda (a b) (> (length a) (length b))))) (defconst remind-type-keywords (sort (list "INT" "STRING" "TIME" "DATE" "SHADE") #'(lambda (a b) (> (length a) (length b))))) (defconst remind-builtin-variables (sort (list "$CalcUTC" "$CalMode" "$DefaultPrio" "$EndSent" "$EndSentIg" "$NumTrig" "$FirstIndent" "$FoldYear" "$FormWidth" "$MinsFromUTC" "$LatDeg" "$LatMin" "$LatSec" "$Location" "$LongDeg" "$LongMin" "$LongSec" "$MaxSatIter" "$SubsIndent") #'(lambda (a b) (> (length a) (length b))))) (defconst remind-time-words (sort (list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday" "Thu" "Thursday" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday") #'(lambda (a b) (> (length a) (length b))))) (defconst remind-builtin-functions (sort (list "abs" "access" "shell" "args" "asc" "baseyr" "char" "choose" "coerce" "date" "dawn" "today" "day" "daysinmon" "defined" "dosubst" "dusk" "easterdate" "easter" "filedir" "filename" "getenv" "hour" "iif" "trigger" "index" "isdst" "isleap" "isomitted" "hebdate" "hebday" "hebmon" "hebyear" "language" "ord" "thisyear" "sunrise" "sunset" "lower" "max" "min" "minute" "mon" "moondate" "moontime" "moonphase" "now" "ostype" "plural" "realnow" "realtoday" "sgn" "strlen" "psshade" "substr" "trigdate" "trigger" "trigtime" "trigvalid" "typeof" "upper" "psmoon" "value" "version" "wkday" "wkdaynum" "msgprefix" "msgsuffix" "year") #'(lambda (a b) (> (length a) (length b))))) ;;; faces ;;example of setting up special faces for a mode. (defvar remind-conf-command-face 'remind-conf-command-face "Remind commands.") (defface remind-conf-command-face '((t :foreground "SeaGreen4" :bold t)) "Font Lock mode face used to highlight commands." :group 'remind-conf) (defvar remind-conf-keyword-face 'remind-conf-keyword-face "Remind keywords.") (defface remind-conf-keyword-face '((t :foreground "blue violet")) "Font Lock mode face used to highlight keywords." :group 'remind-conf) (defvar remind-conf-substitutes-face 'remind-conf-substitutes-face "Remind substitutes.") (defface remind-conf-substitutes-face '((t :foreground "blue2")) "Font Lock mode face used to highlight substitutes." :group 'remind-conf) (defvar remind-conf-endline-face 'remind-conf-endline-face "Remind endline.") (defface remind-conf-endline-face '((t :foreground "goldenrod2" :bold t)) "Font Lock mode face used to highlight commands." :group 'remind-conf) (defvar remind-conf-variable-face 'remind-conf-variable-face "Remind variable.") (defface remind-conf-variable-face '((t :foreground "DeepPink2" :bold t)) "Font Lock mode face used to highlight commands." :group 'remind-conf) (defvar remind-conf-color-face 'remind-conf-color-face "Remind color variables.") (defface remind-conf-color-face '((t :foreground "gold" :bold t)) "Font Lock mode face used to highlight color changes." :group 'remind-conf) (defvar remind-conf-delta-face 'remind-conf-delta-face "Remind deltas.") (defface remind-conf-delta-face '((t :foreground "sandy brown" :bold t)) "Font Lock mode face used to highlight deltas." :group 'remind-conf) (defvar remind-comment-face 'remind-comment-face "Remind comments.") (defface remind-comment-face '((t :foreground "brown")) "Font-lock face for highlighting comments." :group 'remind-conf) (defvar remind-string-face 'remind-string-face "Remind strings.") (defface remind-string-face '((t :foreground "tomato")) "Font lock mode face used to highlight strings." :group 'remind-conf) (defvar remind-time-face 'remind-time-face "Remind time words.") (defface remind-time-face '((t :foreground "LightSeaGreen" :bold t)) "Font lock mode face to highlight time phrases." :group 'remind-conf) (defvar remind-conf-type-face 'remind-conf-type-face "Remind type keywords.") (defface remind-conf-type-face '((t :foreground "orange" :bold t)) "Font lock mode face to highlight type keywords." :group 'remind-conf) (defcustom rem-post-save-function "" "Name of shell function that can be run when you save and close a remind file. If you put a & after the name of the function, it will run asyncronously. This might be useful if the process takes a long time." :type 'string :group 'remind-conf ) ;; keywords (defconst remind-conf-font-lock-keywords-1 (list '("^[\;\#]\\s-+.*$" . remind-comment-face) (cons (regexp-opt remind-keywords 'words) remind-conf-keyword-face) '("%[\"_]" . font-lock-warning-face) '("\\(%[a-mops-w]\\)" . remind-conf-substitutes-face) '("\"[^\"]*\"" . remind-string-face)) "Minimal font-locking for `remind-conf-mode'.") (defconst remind-conf-font-lock-keywords-2 (append remind-conf-font-lock-keywords-1 (list (cons (regexp-opt remind-time-words 'words) remind-time-face) (cons (regexp-opt remind-builtin-functions 'words) remind-conf-command-face) '("%$" . remind-conf-endline-face))) "Additional commands to highlight in `remind-conf-mode'.") (defconst remind-conf-font-lock-keywords-3 (append remind-conf-font-lock-keywords-2 (list (cons (regexp-opt remind-type-keywords 'words) remind-conf-type-face) '("\[[a-zA-Z]\\{3,6\\}\]" . remind-conf-color-face) '("\\s-+\\([12][0-9]\\|3[01]\\|0?[0-9]\\)\\s-+" . remind-conf-substitutes-face);better date regexp '("\\s-+\\(\\(?:20\\|19\\)[0-9][0-9]\\)\\s-+" . remind-conf-substitutes-face);years '("\\s-+\\(2[0-4]\\|[01]?[0-9][.:][0-5][0-9]\\)\\s-+" . remind-conf-substitutes-face);24hour clock, more precise '("\\s-+\\([+-][+-]?[1-9][0-9]*\\)\\s-+" 1 remind-conf-delta-face prepend) (cons (regexp-opt remind-builtin-variables 'words) remind-conf-variable-face))) "The ultimate in highlighting experiences for `remind-conf-mode'.") (defcustom remind-conf-font-lock-keywords 'remind-conf-font-lock-keywords-3 "Font-lock highlighting level for `remind-conf-mode'." :group 'remind-conf :type '(choice (const :tag "Barest minimum of highlighting." remind-conf-font-lock-keywords-1) (const :tag "Medium highlighting." remind-conf-font-lock-keywords-2) (const :tag "Highlighting deluxe." remind-conf-font-lock-keywords-3))) ;;; Indentation (I'm sure this could be made more simple. But at least it works.) (defcustom remind-indent-level 4 "User definable indentation." :group 'remind-conf :type '(integer) ) (defun remind-indent-line () "Indent current line for remind configuration files." (interactive) (forward-line 0) ;remember this happens on every line as it is done per line basis (if (bobp) (indent-line-to 0) (let ((not-indented t) cur-indent) (if (looking-at "^[ \t]*\\<\\(ENDIF\\|POP\\(?:-OMIT-CONTEXT\\)?\\)\\>") (progn (save-excursion (forward-line -1) (setq cur-indent (- (current-indentation) remind-indent-level))) ;note that not-indented is still t (if (< cur-indent 0) (setq cur-indent 0))) (save-excursion (while not-indented (forward-line -1) (if (looking-at "^[ \t]*\\<\\(ENDIF\\|POP\\(?:-OMIT-CONTEXT\\)?\\)\\>") (progn (setq cur-indent 0) (delete-horizontal-space) ;don't know why I need this when other similar indent functions don't. (setq not-indented nil)) (if (looking-at "\\<\\(IF\\(?:TRIG\\)?\\|PUSH\\(?:-OMIT-CONTEXT\\)?\\)\\>") (progn (setq cur-indent remind-indent-level) (setq not-indented nil)) (if (bobp) (setq not-indented nil)))))) (if cur-indent (indent-line-to cur-indent) (indent-line-to 0)))))) ;;; Convenience functions (define-skeleton rem-skel "Skeleton to insert a rem line in a remind configuration file." nil "REM "(skeleton-read "Date? " ) ("Optional: How many days ahead? " " +" str ) resume: ("Optional: At what time? Format eg 13:00. " " AT " str) resume: ("Optional: How many minutes ahead? " " +" str ) resume: ("Optional: At what priority? eg 0-9999" " PRIORITY " str ) resume: " MSG %\"" (skeleton-read "Your message? " )"%b%\"%" \n ) (define-skeleton rem-today-skel "Skeleton to insert a line for today's date." nil "REM " (format-time-string "%d %b %Y") ("Optional: At what time? Format eg 13:20. " " AT " str) resume: ("Optional: How many minutes ahead? " " +" str ) resume: ("Optional: At what priority? eg 0-9999" " PRIORITY " str ) resume: " MSG " (skeleton-read "Your message? " )"%b.%" \n ) (defun rem-today () "Insert the date for today in a remind friendly style." (interactive) (insert (format-time-string "%e %b %Y"))) (defun rem-tomorrow () "Insert tomorrow's date in a remind friendly style." (interactive) (insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time 1))))) (defun rem-days-away (arg) "Insert a day N number of days in the future. Takes a prefix argument, but defaults to 4." (interactive "nHow many Days?: ") (insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time arg))))) (defun rem-week-away () "Insert a day 7 days in the future." (interactive) (insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time 7))))) (setq skeleton-end-hook nil) ; so the skeletons will not automatically go to a new line. ;;; private function ;; could make it useful for others. Put somethin like the following in your .emacs ;(setq rem-post-save-function "~/bin/dailypic &") (defun rem-save-file () "Save the file and start the shell function in one go. This function will close the window after running. It needs the variable `rem-post-save-function' to be set. It will be most useful to people who have some sort of function they run to use remind data ie procucing calendars." (interactive) (if (boundp 'rem-post-save-function) (progn (save-buffer) (shell-command rem-post-save-function) (kill-buffer-and-window)) (error "`rem-post-save-function' variable is not set"))) (defun rem-setup-colors () "Insert set of variables for coloured output in remind messages." (interactive) (find-file (expand-file-name "~/.reminders")) (goto-char 0) ;we do want it somewhere near the top of the file. (save-excursion (re-search-forward "\n\n"); squeeze it in where you have a free line. (insert "\nSET Esc CHAR(27) SET Nrm Esc + \"[0m\" SET Blk Esc + \"[0;30m\" SET Red Esc + \"[0;31m\" SET Grn Esc + \"[0;32m\" SET Ylw Esc + \"[0;33m\" SET Blu Esc + \"[0;34m\" SET Mag Esc + \"[0;35m\" SET Cyn Esc + \"[0;36m\" SET Wht Esc + \"[0;37m\" SET Gry Esc + \"[30;1m\" SET BrRed Esc + \"[31;1m\" SET BrGrn Esc + \"[32;1m\" SET BrYlw Esc + \"[33;1m\" SET BrBlu Esc + \"[34;1m\" SET BrMag Esc + \"[35;1m\" SET BrCyn Esc + \"[36;1m\" SET BrWht Esc + \"[37;1m\" \n \n"))) ;; So now you can do things like: (define-skeleton birthcol "Make birthdays magenta. Acts on the region or places point where it needs to be." nil "[Mag]" _ " [Nrm]") ;; finally the derived mode. ;;;###autoload (define-derived-mode remind-conf-mode text-mode "REM" "Major mode for editing remind calendar configuration files. \\{remind-conf-mode-map}" :syntax-table remind-conf-syntax-table (set (make-local-variable 'font-lock-keywords-case-fold-search) t) ;this is not working atm 2009-04-13 (set (make-local-variable 'font-lock-defaults) '(remind-conf-font-lock-keywords)) (set (make-local-variable 'comment-start) ";") (set (make-local-variable 'comment-start) "#") (set (make-local-variable 'comment-end) "\n") (set (make-local-variable 'fill-column) '100);cause I was having problems with autofill. (set (make-local-variable 'indent-line-function) 'remind-indent-line) (use-local-map remind-conf-mode-map) ) (provide 'remind-conf-mode) ;;; remind-conf-mode.el ends here ;;; Indentation code ;;; work out how to make the syntax highlighting work only before the (MSG|MSF) ;;; keywords and not after. ;;; for my own use. keymap to save file and do dailypic C-c C-c in time honoured tradition?remind-03.01.15/docs/README.UNIX0000644000076400007640000000707012514120337013735 0ustar dfsdfsREMIND version 3.1 for UNIX REMIND is a sophisticated alarm/calendar program. Details are given in the man page, "remind.1". INSTALLING REMIND: ----------------- If you have Tcl/Tk (wish 4.1 or higher) installed and are running X Windows: -------------------------------------------------------------- 1) Type: wish ./build.tk from the top-level Remind directory. Fill in the various options and hit "Build Remind" 2) Type: "make install" -- you may need to be root to do this. If you do NOT have Tcl/Tk or are NOT running X Windows: ------------------------------------------------------- 1) Edit the file "src/custom.h" according to your preferences. 2) Edit the file "src/lang.h" to choose a language. 3) Type: "make" 4) Type: "make install" -- you may need to be root to do this. The subdirectory "www" contains scripts for making a nice calendar web server. See the files README and Makefile in that directory. The file "examples/defs.rem" has some sample Remind definitions and commands, as well as U.S. and Jewish holidays. OTHER LANGUAGE SUPPORT Remind has support for languages other than English. See the file "src/lang.h" for details. The language support may vary - you can change only the substitution filter, or you can translate all of the usage instructions and error messages as well. See "src/langs/french.h" for an example of the latter. To compile Remind for a non-english language, look at the constants defined in "src/lang.h". Then, to compile Remind for Italian (as an example), type: make "LANGDEF=-DLANG=ITALIAN" If you add support for a non-English language, Remind will accept both the English and non-English names of months and weekdays in an input script. However, you should not rely on this feature if you want to write portable Remind scripts. At a minimum, you should support month and day names in the foreign language, and should modify the substitution filter appropriately. If you are truly diligent, you can translate usage and error messages too. Take a look at the files "src/langs/english.h" and "src/langs/german.h" if you want to add support for your favourite language. If you do add another language to Remind, please let me know! Here are the basic guidelines: - Your language file should be called "src/langs/lxxx.h", where lxxx is the first 8 characters of the ENGLISH name of your language. - Your language file should define L_LANGNAME to be the full English name of your language, with the first letter capitalized and the rest lower-case. - You can test your language file with the script "tests/tstlang.rem" RELEASE NOTES -- miscellaneous info that couldn't go anywhere else! 1. POPUP REMINDERS If you're running under X-Windows and you have the TCL tools, you can create simple pop-up reminders by creating the following TCL script called 'popup'. It pops a message on to the screen and waits for you to press the 'OK' button. If you don't press the OK button within 15 seconds, it exits anyway. To use it, you can use the '-k' option for Remind as follows: remind "-kpopup '%s'&" .reminders Or use the following in your Remind script: REM AT 17:00 RUN popup 'Time to go home.' & This Tcl script is a slightly modified version of one submitted by Norman Walsh. -------------- Cut Here ---------- Cut Here ---------- Cut Here ------------- #!/usr/local/bin/wish wm withdraw . after 15000 { destroy . ; exit } tk_dialog .d { Message } $argv warning 0 { OK } destroy . exit -------------- Cut Here ---------- Cut Here ---------- Cut Here ------------- -- Dianne Skoll http://www.roaringpenguin.com/remind/ remind-03.01.15/docs/WHATSNEW0000644000076400007640000013633512555504517013500 0ustar dfsdfsCHANGES TO REMIND * Version 3.1 Patch 15 - 2015-07-27 - BUG FIX: Fix a buffer overflow found by Alexander Keller - BUG FIX: Fix a typo in this file: was 2014 instead of 2015. - BUG FIX: Make parser reject an AT followed by more than one time. - BUG FIX: Make parser reject epeated delta or *repeat values. * Version 3.1 Patch 14 - 2015-04-24 - NEW FEATURE: Putting the line __EOF__ in a .rem file causes Remind to treat it as end-of-file. - IMPROVEMENT: Use better PNG images for moons in the HTML display - CHANGE: Author name updated from "David" to "Dianne" - BUG FIX: The "-n" command-line option should really run in "ADVANCE_MODE" rather than "CAL_MODE" internally; otherwise, the substitution sequences may be misinterpreted. - BUG FIX: A typo in clearing out MD5 sum context has been fixed. - BUG FIX: Typo in Spanish translation was fixed. * Version 3.1 Patch 13 - 2013-03-22 - BUG FIX: Sunrise/Sunset calculations greatly improved thanks to John McGowan. Accuracy should now be within a couple of minutes in most places. - BUG FIX: Allow specification of margins as low as 0 points in rem2ps, courtesy of Jonathan Kamens. - BUG FIX: Permit compilation with gcc 2.95 (which doesn't allow variable declarations after non-declaration statements in a block.) - BUG FIX: Several minor documentation errors corrected courtesy of Simon Ruderich. - BUG FIX: Spurious test harness failure was fixed. * Version 3.1 Patch 12 - 2012-01-23 - NEW FEATURE: Many substitution sequences "%x" have an alternate mode denoted by "%*x". This alternate mode leaves out prepositions. For example, in English "%i" might yield "on 01-25" while "%*i" yields only "01-25". - BUG FIX: The "dusk" and "dawn" calculations were completely wrong. They have been fixed. Also, sunrise/sunset calculations have been tweaked, so the results may be off by a minute or two compared to previous versions of Remind. * Version 3.1 Patch 11 - 2011-12-16 - BUG FIX: For some inexplicable reason, dawn was considered to happen when the sun was 14 degrees below the horizon instead of the standard 6 degrees for Civil Dawn. This has been fixed. - BUG FIXES: Clarified the man pages and fixed some typos. - BUG FIX: Add THROUGH to the remind.vim syntax highlighting file. - ENHANCEMENT (?): Allow SPECIAL COLOR to be spelled SPECIAL COLOUR. - BUG FIX: Apply minor Debian cleanups reported by Kurt B. Kaiser. * Version 3.1 Patch 10 - 2010-11-01 - NOTE: This is the 20th anniversary of Remind's first public release. - ENHANCEMENT: Add the THROUGH keyword. You can omit blocks of dates with: OMIT start THROUGH end and the syntax REM start THROUGH end is equivalent to REM start *1 UNTIL end - ENHANCEMENT: Add support for multibyte characters (eg, UTF-8) in calendar output. Note that UTF-8 strings are still not supported in PostScript output. - ENHANCEMENT: Add support for UTF-8 line-drawing characters in calendar output. - ENHANCEMENT: You can have multiple TAG clauses in a REM statement. - BUG FIX: Avoid spawning long-running background processes in "make test". - BUG FIX: Don't declare variables in the middle of statements (old C compilers choke.) * Version 3.1 Patch 9 - 2010-06-20 - MAJOR ENHANCEMENT: New "purge mode" to delete expired reminders. See the PURGE MODE section of the remind man page. - ENHANCEMENT: Support DURATION in TkRemind. Thanks to Marek Marczykowski. - BUG FIX: Don't change the order of PS and PSFILE reminders. Bug found by John McGowan. - BUG FIX: "REM 1990-01-01 SATISFY 1" would yield a spurious parse error in earlier versions of Remind. - BUG FIX: Yom HaShoah is moved to Thursday if it would normally fall on a Friday. Thanks to Jonathan Kamens for pointing this out. * Version 3.1 Patch 8 - 2010-03-09 - ENHANCEMENT: Include some useful scripts in contrib/ - ENHANCEMENT: Add the $T, $Td, $Tm, $Tw, $Ty, $U, $Ud, $Um, $Uw, $Uy special variables to make reminder files less wordy. See man page for details. - MINOR ENHANCEMENT: Set an icon photo window manager resource on TkRemind. - POLICY CHANGE: Discourage use of Remind on MS Windows or Apple Mac OS X. - BUG FIX: Ignore msgprefix() and msgsuffix() on RUN-type reminders. - BUG FIX: Adjust Remind and Rem2PS so that SHADE specials don't obliterate earlier MOON specials. - BUG FIX: Fix bug in SCHED calculations if Remind is started in the middle of a SCHED interval. * Version 3.1 Patch 7 - 2009-05-31 - ENHANCEMENT: Wherever you could write "day Mon year", the parser now accepts "YYYY-MM-DD". This applies on the command-line and to the REM and OMIT keywords. You can avoid wrapping date calculations in the trigger() function in many cases. - ENHANCEMENT: New slide() built-in function eases some complicated reminders. * Version 3.1 Patch 6 - 2008-11-16 - MAJOR ENHANCEMENT: A new OMITFUNC clause gives you additional control and flexibility over "omitted days" calculations. This is useful when holidays influence the timing of events several days later. See "COMPUTED LOCAL OMITS" in the man page. - ENHANCEMENT: The new evaltrig() built-in function lets you evaluate triggers from within an expression. - ENHANCEMENT: The new weekno() built-in function returns the ISO 8601 week number of a date. - ENHANCEMENT: The "WEEK" special lets you annotate calendar output with the week number. The TkRemind, rem2ps and rem2html back-ends support WEEK. - MINOR ENHANCEMENT: You can control whether timed reminders come before or after non-timed reminders with the "-g" flag. - BUG FIX: TkRemind did not work correctly if ~/.reminders was a directory. - BUG FIX: TkRemind incorrectly invoked Remind with the "-a" flag when showing today's reminders. - BUG FIX: In certain cases, a trigger containing a day, month and weekday would fail if it needed to cross a year boundary. This has been fixed. * Version 3.1 Patch 5 - 2008-04-15 - MAJOR ENHANCEMENT: If you supply a directory name on the command line or for an INCLUDE command, then Remind reads all *.rem file in that directory (in the order returned by "glob") - ENHANCEMENT: The plain-text calendar ("-c") can draw lines using VT-100 line-drawing characters if invoked as "-cl" - ENHANCEMENT: The plain-text calendar can approximate SPECIAL COLOR reminders using VT-100 color escape sequences if invoked as "-cc". (You can combine the colors and line-drawing characters with -clc or -ccl.) - ENHANCEMENT: The "-t" option can take a numeric argument n. In this case, all reminders are assumed to have a delta of +n. (Without the argument, an infinite delta is assumed, as before.) If a numeric argument is given, the new system variable $DeltaOffset is set to the argument. - MINOR ENHANCEMENT: The "-i" command-line option can be used to define a function as well as set a variable. - MINOR ENHANCEMENT: String constants can have embedded quotes "Like \"this" - MINOR ENHANCEMENT: tkremind works better on small screens like that of the Eee-PC. - BUG FIX: Minor fix to HTML output courtesy of Ian! Allen. - BUG FIX: Parse error in calendar mode was fixed. * Version 3.1 Patch 4 - 2008-02-03 - ENHANCMENT: tkremind respects the "-b1" option and operates in 24-hour clock mode if the option is supplied. - ENHANCEMENT: tkremind has been tweaked to look better with Tcl/Tk 8.5. - CLEANUP: Version is kept only in configure.in instead of two different places. - CLEANUP: Added "const" qualifier to many places in the code that previously lacked it. - BUG FIX: A rare parsing error involving interaction between SATISFY and SKIP has been fixed. - BUG FIX: rem2html would output a horribly-wrong calendar for a 28-day February starting on Sunday (such as February 2009.) This has been fixed. - BUG FIX: The "-ivar=value" command-line option failed if Remind re-execed itself because we overwrote argv[]. This has been fixed. * Version 3.1 Patch 3 - 2007-10-15 + MINOR ENHANCEMENTS - rem2html now uses CSS for a much better-looking calendar. NOTE: rem2html was completely rewritten and some of the command-line options have changed! - If a reminder has a DURATION clause, then the starting and ending times are output in calendar mode. + BUG FIXES - DST rules in "defs.rem" were updated to reflect new US/Canadian DST rules. - If a REM command cannot compute a trigger date, the SATISFY expression is not evaluated. This helps avoid spurious error messages in some reminders. * Version 3.1 Patch 2 - 2007-09-12 + MINOR ENHANCEMENTS - build.tk tries to set defaults for location, paper size, etc from an existing "remind" installation if it detects one. - In queue mode, wake up once a minute and recalibrate sleep time. This should make Remind work better on laptops that suspend or hibernate. Note that "remind -q" does *not* handle date-rollover well; it simply exits if it notices date rollover. "remind -z0" (as used by tkremind) handles date rollover properly; it rereads the reminder file and rebuilds the queue if it notices date rollover. - tkremind: Added some key bindings to make navigation easier. - tkremind: Made calendar boxes use space more efficiently. - remind: The functionality of "rem" is now built into remind. If you invoke remind as "rem", then it uses a default filename. The installer sets up "rem" as a symbolic link to "remind". + CHANGE - "remind -p" no longer sorts SPECIAL reminders before non-SPECIAL. *** THIS MAY AFFECT BACKENDS *** Backends supplied by Roaring Penguin (rem2ps, rem2html and tkremind) are known to work properly. - "remind -p" no longer suppresses any AT-time associated with SPECIAL reminders. *** THIS MAY AFFECT BACKENDS *** Backends supplied by Roaring Penguin (rem2ps, rem2html and tkremind) are known to work properly. + BUG FIXES - examples/defs.rem: A few corrections to Jewish holidays courtesy of Art Werschulz. - src/Makefile.in: Added install-nostripped target. - SPECIAL COLOR now works more like MSG, including proper support for AT and for the %" %" escape sequence. - SPECIAL COLOR is queued correctly if it has an AT clause. - Using the psshade() or psmoon() functions emits a warning on stderr. You should use SPECIAL SHADE or SPECIAL MOON instead. * Version 3.1 Patch 1 - 2007-08-23 + MAJOR ENHANCEMENTS - Added the "nonomitted" function that solves a number of moving-reminder-in-response-to-holiday problems. The real-world problems solved are the "moving-garbage-day" problem and the "six-day-school-cycle" problem. + MINOR ENHANCEMENTS - A few minor performance improvements in response to profiling runs. + BUG FIXES - Prevent compilation failure with gcc 2.95. - Fix trailing "s" bug with -k option. This was fixed in Debian's release, but the Debian maintainer never bothered to let me know. - Removed obsolete scripts: kall, rem, remind-all.sh, remind-all.csh - Made "-n" output always use "/" as date separator for consistency with "-p" and "-s". - Moon PNG images are transparent. Output of moon phases in rem2html improved slightly. - Various man-page fixes. * Version 3.1 Patch 0 - 2007-07-14 + MAJOR ENHANCEMENTS - Added the FROM clause. This lets you write reminders like: REM Mon FROM 16 July 2007 UNTIL 13 Aug 2007 MSG Some Mondays... - Remind now has a new datatype: A DATETIME object represents a date AND a time (to the nearest minute). DATETIME constants are written as '2007-09-01@14:33'. Various operators and functions have been modified to do sensible things with DATETIMEs and several new DATETIME functions have been added. - The SPECIAL COLOR reminder type has been hacked to behave more like a MSG type. It sorts properly and is emitted as a normal reminder in non-calendar mode. Simlarly, SPECIAL HTML sorts with -g as well. + MINOR ENHANCEMENTS - TkRemind can e-mail you reminders if you don't dismiss the popup window after one minute. This is useful if you need to leave your workstation but want reminders to "follow" you via e-mail. - A new "-y" option to Remind generates tags for all reminders that lack a TAG clause. This may be useful for conversion tools that want each reminder to have a unique identifier. - A new "tzconvert" function lets you convert datetimes between different time zones. It's only as good as your C library, so test thoroughly please! Based on a patch from Stefan Wehr. - TkRemind sorts reminders by invoking Remind with the '-g' option. - The time and date separator characters can be changed at runtime by setting $TimeSep and $DateSep respectively. - The simple calendar ('-s') option can be immediately followed by an 'a'. This causes Remind to output reminders with deltas before the actual trigger date. Based loosely on an idea from Frank Terbeck. + MINOR CHANGES - Default date separator is now '-' instead of '/' - trigdate() and trigtime() behave differently - they return the integer 0 if the last reminder could not be computed or did not have an AT clause (respectively). - Maximum length of variable names has been increased from 12 to 16 characters. + BUG FIXES - Fixed a potential memory leak in queue.c - Fixed compile error on Mac OS X. - Fixed behaviour of "-sa" option so deltas correctly obey omitted days and the scheduling function (if one is used). - rem2ps would produce invalid PostScript in some rare cases (eg, for February 2007). This has been fixed. * Version 3.0 Patch 24 - 2005-11-19 + MINOR ENHANCEMENTS - Permit the DURATION of a reminder to be as high as you like. Previously, DURATIONs could be at most 23:59. Fix courtesy of Paul Pelzl. - The "-n" flag can be usefully combined with "-s", "-p" and "-l" now. Fix courtesy of Paul Pelzl. + BUG FIXES - The "-k" command escapes all characters except those known to be safe, rather than attempting to escape only characters thought to be unsafe. - Removed the crufty code that supported non-ANSI C compilers. - Removed all support for non-UNIX/non-Linux systems. - Fixed a bug in the tokenizer that could make Remind segfault. Fix courtesy of Stan Tobias. * Version 3.0 Patch 23 - 2005-04-14 + MINOR ENHANCEMENTS - Added the COLOR special for putting colored reminders in the calendar. Supported by the HTML, Tcl/Tk and PostScript back-ends. - Many minor tweaks to tkremind. - Added ability to specify paper size in inches or centimetres to rem2ps. - Added the "-l" option to Remind. This outputs additional information for back-end programs that use the "-p" output format. Currently used only by the "tkremind" back-end. - Fixed dates for Yom Hazikaron and Yom Ha'atzmaut if 5 Iyar falls on a Saturday. (Hebrew calendar fix.) - Added support for the Icelandic language, courtesy of Bjrn Davsson. + BUG FIXES - Fixed parser error for unterminated date constant: '2005/01/01 * Version 3.0 Patch 22 - 2000-06-16 + MINOR ENHANCEMENTS - Added option to have TkRemind display all of today's reminders in a text box on startup. This option is on by default. - Makefile in "www" directory allows you to add ".cgi" suffix to CGI scripts. - Added option to completely delete a reminder from the reminder file in the timed reminder popup dialog. - Clarified build instructions. + BUG FIXES - Fixed packing order in TkRemind so resizing window doesn't make control buttons disappear. - Fixed serious bug in which background queued reminders were ignored and Remind simply exited. Doh! Sorry about that. * Version 3.0 Patch 21 - 2000-03-15 + MINOR ENHANCEMENTS - Updated copyright years and contact info. - Changed GIF images to PNG to avoid patent problems. - Added "cm2trem.tcl" to convert from CDE's "cm" calendar manager to Remind format. It handles only an older version of "cm" data; there is a utility available (under Solaris anyway) to convert newer files to the older "cm" format. - Fixed the scripts in the "www" directory to install and work properly. - Added "remind.vim" file for Vim syntax highlighting of Remind files, thanks to Davide Alberani. - Added "dusk" and "dawn" built-in functions, thanks to Ron Aaron. + BUG FIXES - Files for no-longer-supported platforms (OS/2, amiga, MS-DOS) have been moved to OBSOLETE subdirectory. They will disappear unless someone wants to maintain them. - Fixed typo which caused compilation failure on compilers without function prototypes. Thanks to Ian Darwin for the patch. - Fixed compilation problem on FreeBSD, IRIX, Tru64 and other UNIXes. * Version 3.0 Patch 20 - 1999-04-12 + NEWS - I have started a company, Roaring Penguin Software Inc. (http://www.roaringpenguin.com) and it now holds the Remind copyright. + LICENSE CHANGE - Remind is now distributed under the pure GPL. See the file WINDOWS for my feelings about a Windows port, however. + MINOR ENHANCEMENTS - Made TkRemind adjust for really low-resolution displays if necessary. - Added more print options to TkRemind, courtesy of Niels Kristian Bech Jensen. - Added Spanish language support, courtesy of Rafa Couto. + BUG FIXES - Changed copyright notices to Roaring Penguin Software Inc. - Rem2PS was passing specials like HTML, etc. in PostScript output. YECH! Fix courtesty of Derek J. Decker. - Fixed a typo in danish.h, courtesy of Niels Kristian Bech Jensen. * Version 3.0 Patch 19 - 1998-05-09 + MAJOR ENHANCEMENTS - Added MOON and SHADE specials. These now work with PostScript, HTML and Tcl/Tk front-ends. You can have cute moons and shaded boxes on your printer, on your screen and in your web browser. :-) - TkRemind overhauled -- you can now edit and delete reminders from the GUI. You can actually reasonably use Remind without learning the scripting language. - TkRemind overhauled -- "server mode" added to Remind; TkRemind will now pop up timed reminders. + MINOR ENHANCEMENTS - Updated romanian.h, courtesy Liviu Daia. + BUG FIXES - Allowed object files to be built in different directory from source files (thanks to Jonathan Kamens - Removed restriction against reading group-writable files. This caused headaches on Red Hat Linux which uses an unusual user/group scheme. - Remind would not compile if a non-English language was selected. - Fixed free() of a NULL pointer. - Made tkremind display a helpful error message if Remind's "security feature" of not reading a group-writable file kicks in. - Fixed bug which sometimes prevented reminder times from appearing in a calendar display. - Lots more silly little bugs squashed -- too many to go into in detail. * Version 3.0 Patch 18 - 1998-02-15 + MAJOR ENHANCEMENTS - Added the script "build.tk" which makes it trivial to compile and install Remind under UNIX -- no need to edit Makefiles or header files. A nice GUI installation dialog! - Got rid of all fixed-size buffers. Hurray! Everything is dynamic -- no built-in limits on line length, token size, etc. This should cure lots of SEGV's for weird files. - Added TAG and DURATION clauses for communicating more information to back-ends and eventually converting REMIND into a full-fledged scheduler. - Completely reworked the PS/PSFILE mechanism to use the more general SPECIAL mechanism for customizing output in REMIND back-ends. + MINOR ENHANCEMENTS - Made parser _very_ forgiving -- the type of reminder now defaults to MSG. This lets you have lines in the reminder file like this: Feb 9, 1998 Meeting with Joe. But I don't recommend abusing it. It's mostly to ease migration from UNIX calendar(1) files. - Documented the "remind -p" format. - Made Remind communicate day and month names to back-ends so they can automatically take on the language Remind was compiled with. - Directory structure totally reorganized. Remind now uses an autoconf "configure" script which should make life very pleasant for UNIX people. - Made Rem2HTML work properly if more than one month's worth of calendar data was produced. Rem2HTML also escapes any special HTML characters. However, it recognizes a "SPECIAL HTML" type of reminder which lets you put arbitrary HTML code in your calendar entries. See www/rem2html for details. - Added the "-a" option to Rem2HTML to complement the "-p" option. Also made Rem2HTML print a usage message if input is coming from a terminal. + BUG FIXES - Fixed sunset(), sunrise() and minsfromutc() functions which were broken by 3.0.17. (In 3.0.17, they did not account for daylight saving time.) - Updated "finnish.h" to include proper URL and translation of all error messages. + BUG INTRODUCTIONS - The reorganization and use of "configure" probably breaks Remind installation on non-UNIX platforms. Sorry. I can't fix it until I hear back from non-UNIX maintainers. - Getting rid of fixed-sized buffers meant lots of changes to code. No doubt, I missed a few regression tests. * Version 3.0 Patch 17 - 1997-09-07 + MINOR ENHANCEMENTS - Made REMIND accept date specs like "Jan 6, 1998" -- the comma is ignored. This was suggested by John Conover . You can even do "REM 27, Aug, 1998, msg bar". (But I don't know why you'd want to.) - Added www/rem2html, a Perl script which converts the output of `remind -p ...' to an HTML table. The script was contributed by Don Schwarz - New security features: Because of the risks of statically-allocated buffers, REMIND now refuses to run if it is installed set-uid or set-gid. If REMIND is run as root, it refuses to read files not owned by root. It also won't open group- or world-writable files, no matter who is running it. Finally, if you read a file you don't own, REMIND disables RUN and shell(). REMIND doesn't do these security checks on stdin, though, so be careful if you run it as root in a script. NOTE: REMIND doesn't do the world- and group-writable checks on devices, FIFOs, etc. Otherwise "remind /dev/null" fails... + BUG FIXES - Increased sizes of some statically-allocated buffers. This doesn't really fix the problem, but makes it more manageable. - Using the "-u" option now implies the "-r" option. This is a security feature. - Added romanian.h to the manifest. Sorry. - CalcMinsFromUTC was failing if time_t was unsigned. I now use difftime(), but not all systems have it. Also, defs.rem was rearranged so PostScript stuff works better, and new target "emxomf" was added to makefile.os2 which uses OMF linking and a dynamically-linked C library. All three of these fixes are courtesy of Christopher J. Madsen . Thanks, Christopher. * Version 3.0 Patch 16 - 1997-02-11 + MINOR ENHANCEMENTS - Bundled scripts for making a nice WWW calendar server. See the "www" subdirectory in the release. - Added support for the Romanian language, courtesy of Liviu Daia. - Changed sunrise() and sunset() as follows: If the sun never rises, sunrise() returns 1440 and sunset() returns 0. In this case, sunrise()-sunset() returns the length of the dark period of the day, in minutes. If the sun never sets, sunrise() returns 0 and sunset() returns 1440, and sunset()-sunrise() returns the length of the light period of the day, in minutes. Thanks to Michael Salmon for explaining the utility of this. See the file "defs.rem" for the functions _light_len and _dark_len which return the length in minutes of the light and dark period of the day, respectively. + BUG FIXES - If you used the "-g" option, then no background reminders were ever issued. DOH! Thanks to Greg Badros for pointing this out. - Fixed a problem under Solaris 2.5 whereby rem2ps was skipping some latin1 characters which it interpreted as white space. * Version 3.0 Patch 15 - 1996-10-27 + IMPORTANT NOTES - The tar file now unpacks into a Remind subdirectory rather than into the current working directory. - I no longer support Remind under DOS. I don't think I've done anything to stop it from working under DOS, but will no longer compile and test it under DOS, and can't help you if you get stuck. Sorry -- I no longer have a DOS machine. + MINOR ENHANCEMENTS - Changed psshade() to accept 1 or 3 arguments for colored shading in PostScript calendar mode. - Added a Print dialog to tkremind. - Added support for Brazilian Portuguese courtesy of Marco Paganini - Added support for Italian courtesy of Valerio Aimale + BUG FIXES - Fixed confusing error in rem2ps help messages. - Fixed bug in TkRemind which caused a crash if the "-m" option was used for a month beginning on Sunday. Doh!!! * Version 3.0 Patch 14 - 1996-05-25 + CHANGE IN COPYING POLICY - Remind is now distributed under an _AMENDED_ version of the Gnu General Public License. These amendments are listed in the file COPYRIGHT. The amendments were made for personal reasons; please don't ask me to explain them. They probably don't affect you, anyway. + MAJOR ENHANCEMENTS - Added an X-Windows front-end to Remind. To use it, you must be running under X-Windows on UNIX, and have the "wish" tcl/tk interpreter, version 7.4 of tcl and 4.0 of tk. The front-end is called "tkremind". + MINOR ENHANCEMENTS - Added the WARN keyword for precise advance notice. You can now have advance warning 5, 3, 1 and 0 days in advance (for example.) The WARN keyword operates similarly to the SCHED keyword in that it calls a user-defined function to obtain the advance warning sequence. - Added support for QDOS/SMSQ on the Sinclair QL microcomputer, courtesy of Robert H. Klein NOTE THAT I CANNOT TEST NOR SUPPORT THIS VERSION! - Added support for AmigaDOS / SAS/C, courtesy of Martin Hohl . As before, I CANNOT TEST NOR SUPPORT THIS VERSION, but will rely on feedback from others. + BUG FIXES - Removed the "-n" option from Rem2PS. Instead, if you want the PostScript calendar to start on a Monday, supply the "-m" option to Remind. It was repugnant to have two options to two programs to accomplish one thing. - The "hebdate" built-in function worked incorrectly with 5 arguments. The bug was pointed out by Hershel Safer - This would hang up REMIND: REM Mon 31 Feb MSG Foo and this would fail quietly: REM Mon 31 Feb 1996 MSG Foo Both have been fixed and now report bad date specifications. - Remind now compiles without complaint under gcc -ansi -Wall -pedantic (on my Linux system, anyway!) + IMPORTANT NOTE - I had problems building the DOS version with Turbo C. I have access only to ancient versions of Turbo C and Microsoft C. Remind built fine with Microsoft C, but the TC version hung up. I am not too interested in maintaining the DOS version, so when the MSC compiler no longer works, I will drop DOS support. Please not that I will _not_ support MS Windows, and in fact do not allow Remind to run under Windows (see COPYRIGHT). * Version 3.0 Patch 13 - 1994-05-06 + MINOR ENHANCEMENTS - Added extra parameters to the "psmoon" built-in function so you can annotate the PostScript moon icons. - Added a command-line "time" argument to Remind for testing Remind scripts with specific system times. Also added the realnow() function which has the same relationship to now() as realtoday() has to today(). (See the man page!) - Modified Rem2PS so it prints progress messages to stderr if '-v' command-line argument is used. - In the top of the 'finnish.h' file, added a note about Mikko Silvonen's file of Finnish holidays. + BUG FIXES - Fixed a bug in rem2ps which sometimes caused incorrect PostScript if the -e and -m options were used. Thanks to Michael Neuhauser for reporting the bug and providing a fix. - Made the '-k' option escape shell characters in the message to make it safer. - Fixed a segmentation violation which resulted if not all PUSH-OMIT-CONTEXTs were balanced by POP-OMIT-CONTEXTs. - Removed the prototype for DestroyValue, which is now a macro. I'm amazed that very few compilers complained about this one! - Updated the copyright notices everywhere. * Version 3.0 Patch 12 - 1994-02-01 + MINOR ENHANCEMENTS - Added support for the Danish language, courtesy of Mogens Lynnerup. - Added support for the Polish language, courtesy of Jerzy Sobczyk. - Made the Makefile more portable, thanks to Jim Budler. - Removed some compiler warnings under Linux, thanks to Francois Pinard. - Tidied the man page a bit; added a small bibliography. + BUG FIXES - Fixed a problem with the '-k' option which resulted in a newline being placed after the message text. This was giving sh(1) heartburn... * Version 3.0 Patch 11 - 1993-11-26 + MINOR ENHANCEMENTS - Added release notes to README.UNIX and README.OS2 describing one way to make pop-up alarms under X-Windows and Presentation Manager. - Added the $DefaultPrio system variable - Improved OS/2 support, thanks to Darrel Hankerson, Russ Herman and Norman Walsh. - Made the pushing and popping of operators and operands during expression evaluation in-line code instead of function calls. Did the same for DestroyValue. I'm not sure if this was a good idea -- on the Sparc using gcc, this slowed things down... go figure. + BUG FIXES - Fixed a potential memory leak in the char() function. - Made the TRIGGER() built-in function return its answer in English even for the foreign-language versions -- this was required for compilers which are not 8-bit clean, and for languages with accented letters. - Made expression evaluation slightly faster by eliminating some unnecessary copying of string values. - Corrected some non-portable definitions of the macro UPPER(c) - Fixed typos in french.h * Version 3.0 Patch 10 + MAJOR ENHANCEMENT - OS/2 support is now much better, thanks to Russ Herman. The Borland C compiler under OS/2 and MS-DOS is supported. + MINOR ENHANCEMENTS - Added the SCHED keyword for precise control of scheduling of timed reminders -- it's really quite nifty! - Modified the trigger() function to take up to three arguments -- in addition to a date, you can specify a time and a flag specifying that the trigger should be converted from UTC to local time. - Added $SortByDate, $SortByTime and $SortByPrio system variables. - Added test suites for MS-DOS and OS/2, courtesy of Russ Herman. - In PostScript output, the month and year are output in the %%Page: comments. Makes it nicer to view multi-month calendars with previewers (eg, GhostView.) - Added the PRIORITY keyword for more control of sort order of reminders. Based on a suggestion by George M. Sipe. - Added the msgprefix() and msgsuffix() evaluations around MSG-type reminders for doing fancy things with reminders of different priorities. Also added calprefix() and calsuffix() for doing the same thing in calendar mode. - Enabled the -g option during calendar mode as well as regular mode. + BUG FIXES - Fixed minor bugs in the LocalToUTC and UTCToLocal functions. - "remind -c -de file" used to cause a segmentation violation. Whoops... - Some files which should have included didn't include it - these are now fixed. - Fixed the moondate() and moontime() functions, which used to be incorrect after November 1994. - Fixed the Finnish language support which was missing a few newlines. * Version 3.0 Patch 9 - 1993-10-04 + NOTES - Remind is now too big to compile under the "small" model in MS-DOS. You must recompile everything under the "medium" model. + MAJOR ENHANCEMENTS - Functions moonphase(), moondate() and moontime() were added for dealing with phases of the moon. The code was snarfed from "moontool" by John Walker - see the file "moon.c" for detailed acknowledgement. Also added psmoon() for putting little moon symbols on the PostScript calendar. + MINOR ENHANCEMENTS - Added some more examples to defs.rem - notably, support for ANSI terminal color-changing escape sequences, thanks to Gail Gurman. - Modified both Remind and Rem2PS so that calendars can start on Sunday or Monday, depending on your preference. Unfortunately, the command-line options are different -- for Remind, it's '-m' and for Rem2PS it's '-n' because '-m' was already in use. Based on a suggestion by John Plate and a patch sent by Mikko Silvonen. - The Finnish language support is better - now, all usage and error messages are in Finnish. In addition, the Finnish language module supports the IBM extended character set as well as ISOLATIN1. Thanks to Mikko Silvonen. - Modified Rem2PS to allow more control over the placement of the small calendars, thanks to a suggestion by Frank Vance. Also added option to control the calendar title (e.g., "September 1993") independently of day-of-week headings. - Added the psshade() function to make it easier to shade PostScript calendars. - Allowed a repeat parameter '*num' to be supplied on command line so a 'preview' of many days' worth of reminders can be obtained easily. - Added the $Location system variable. - Allowed an expression to be supplied to EXIT to return an exit status. - Added the FLUSH command. + BUG FIXES - Fixed the MSF-type reminder to fill paragraphs more intelligently. It puts double spaces after '!', '.' and '?', and can handle quotes, brackets, etc. after periods, etc. These characters can be specified with the $EndSent and $EndSentIg system variables. Also modified it so that newlines in the body start new paragraphs, rather than being swallowed as white-space. * Version 3.0 Patch 8 - 1993-09-08 + MAJOR ENHANCEMENTS - Changed the code to more fully support foreign languages - error messages and usage instructions can now be changed. All changes can be localized in the appropriate language.h files. - Added support for the French language, courtesy of Laurent Duperval. Note that the French support is more complete than for other languages - French usage instructions and error messages are supported. - Added support for the Norwegian language, courtesy of Trygve Randen. + MINOR ENHANCEMENTS - Added code for the functions timelocal() and timegm(), courtesy of Lucio de Re. This is for those very few machines whose libraries include neither those functions nor mktime(). - Added the filedate() function. - Allowed the filename to be specified as "-" to cause Remind to take its input from the standard input stream. - Added the "MSF" keyword to cause reminders to be formatted automatically. This keyword paragraph-fills reminder text following user specifications. Based on a suggestion by Ken McGlothlen. - Added the "-e" option to Rem2PS, allowing the PostScript calendar to fill the entire page. Thanks to Arthur G. Yaffe. + BUG FIXES - Corrected the Hebrew holidays Tzom Gedalia, Tzom Tevet, Ta'anit Esther, Tzom Tamuz and Tisha B'Av so they won't occur on Saturday. Corrections made following the algorithm in "Calendrical Calculations" by Nachum Dershowitz and Edward M. Reingold. - Changed the dutch.h language file as suggested by Erik-Jan Vens. Made month and day names lower-case; corrected the spelling of oktober. - Changed HashVal in var.c to use unsigned arithmetic - it's conceivable that a machine with signed chars could cause problems otherwise. - Changed the LONG_* macros in config.h to LON_* to avoid conflicts with names defined by ANSI C. Thanks to David W. Sanderson. - Allowed the built-in function char() to accept numbers in the range [-128, 255] (but not 0) so that char(asc(s)) works even on machines with signed char types. * Version 3.0 Patch 7 - 1993-07-22 + MAJOR ENHANCEMENTS - Added "system variables" to allow the user more control over Remind operation, and to allow queries about the command-line options from within a reminder script. They allow for specification of longitude and latitude for use by sunrise/sunset calculations. - Added sunrise(), sunset(), isdst() and minsfromutc() functions - these are needed to support sunrise and sunset calculations. + MINOR ENHANCEMENTS - Allowed the MSG, RUN, CAL, PS and PSF keywords to be used in the same reminder as the SATISFY keyword. This makes many complex reminders more compact. - Added the filedir() function to enable Remind's include to emulate CPP's #include more closely. - Allowed non-root users to use the "-u" option. It only affects the "SHELL", "HOME", "USER" and "LOGNAME" environment variables - it doesn't change the effective uid and gid when run by non-root. - Added built-in function "easterdate" to calculate date of Easter Sunday - function courtesy of Michael Salmon. - Improved the Jewish holiday reminders in "defs.rem" to give advance notice of holidays. - Allowed the "simple calendar" option (-s) to specify a number of weeks as well as a number of months, in the same fashion as the -c option. Thanks to Dave Rickel. + BUG FIXES - Corrected the behaviour of "hebdate" for jahrzeits; added an additional parameter to specify the behaviour of dates in Adar during leap years. - Changed kall so that "kall sh" doesn't commit suicide - patch courtesy of Michael Salmon. * Version 3.0 Patch 6 - 1993-05-05 + MINOR ENHANCEMENTS - Added the PS- and PSFILE-type reminders - these allow you to include arbitrary PostScript code in your PostScript calendars. Useful for shading, drawing graphics on calendars, etc. Use with care, though! - Added the "-ivar=val" option to initialize variables from the command line. Changed the remind-all.* shell scripts to predefine the variable "remind_all". + BUG FIXES - Fixed a bug in the hebmon(), hebday() and hebyear() functions - there was an off-by-one error. Sorry! - Fixed a bug in the hebdate() function which resulted in infinite loops for dates after about 2075 - Fixed a bug in the -u option which sometimes caused a core dump (embarrassed grin!) The fix is due to Tina Hoeltig. Thanks, Tina! * Version 3.0 Patch 5 - 1993-04-27 + MAJOR ENHANCEMENTS: - Added support for the Hebrew calendar - can now specify Jewish holidays easily. Thanks to Amos Shapir for explaining the Hebrew calendar, and to Danny Sadinoff, from whose HEBCAL program I got some inspiration. Also thanks to David W. Tamkin and Frank Yellin for explaining the rules for jahrzeits. + MINOR ENHANCEMENTS: - Allowed the default page size used by Rem2PS to be selected in config.h - Edited the defs.rem file to contain Jewish holidays. Cleaned up some of the examples and improved the layout - thanks to George M. Sipe. - Modified the IIF function to be more general - Updated finnish.h to support the ISO 8859-1 character set, courtesy of Mikko Silvonen. - Changed the date conversion routines to greatly speed up conversion from Julian to yyyy/mm/dd form. + BUG FIXES: - Fixed a bug in which Remind complained incorrectly about a missing quote in the command SET foo "" - Fixed bugs in dosubst.c which caused the %o, %1 and %@ substitutions to be incorrect - Fixed a bug in the man page - thanks to Ed Oskiewicz. * Version 3.0 Patch 4 - 1993-03-08 - Added the -g option - this sorts reminders by date/time before issuing them. (You can see I'm running out of letters to name options!) This feature was suggested by George M. Sipe, Paul D. Smith, and Francois Pinard. - Added the "args()" and "dosubst()" built-in functions - see the man page for details. - Added more support for the ISO 8859-1 character set, and modified the german.h file to take advantage of this, thanks to Robert Joop. - Allowed any character to be used as date and time separator characters (not just "/-:.") - Added support for the Dutch and Finnish languages, thanks to Willem Kasdorp and Mikko Silvonen. (Anyone care to contribute French? Italian? Spanish?) - Made Remind issue a warning if you try to redefine a built-in function. This warning is disabled in 'Hush' mode. - Added the SCANFROM clause to the REM command. This allows reasonably safe moveable OMITs such as the Labour Day example in the manual. - Added more examples to the defs.rem file, and cleaned up some old examples. Note that there are now safe moveable holidays for most U.S. holidays provided in the defs.rem file. - Added the '-k' option, which allows MSG-type reminders to be passed to any system command. (Idea and patch courtesy of Philipp Slusallek.) - Allowed selection of ':' or '.' as time separator characters at compile-time. - Edited the COPYRIGHT file to clarify the rules. Please read them. - Removed hard-coding of "am" and "pm" and placed them in language-specific header files as #defines L_AM and L_PM - Fixed a bug in the FindToken() routine which had, through sheer luck, never been activated until the SCANFROM clause was added! - Fixed the UNTIL clause to check for a valid expiry date. - Removed identifiers in the C source beginning with "_" to conform to ANSI practice. - Fixed a bug in the -u option which resulted in environment variables SHELL and USER not being set correctly. Also made -u set the LOGNAME environment variable. - Fixed a couple of typos in the man page; added LDFLAGS to the Makefile. (Thanks to Dave Wolfe.) - Put my new mailing address in the README files. * Version 3.0 Patch 3 - 1993-02-21 - Corrected bugs in Remind and Rem2PS. No new features added. You should NOT use patch level 2 - either stick to 3.0.1 or upgrade to 3.0.3. * Version 3.0 Patch 2 - 1993-02-04 - Added the -u option to Remind so that root can run it as any user. This simplifies the remind-all scripts, and makes them more efficient. If you are worried that this option is a security hole, you can disable it in config.h - Changed the RUN command so that RUN OFF can be used anywhere, even though RUN ON only works in the top-level file. This eases the management of global files which may want to switch RUN OFF. - Added ISO encoding (ISO 8859-1) to the PostScript output, courtesy of Michael Salmon. This can be selected with the '-i' option in rem2ps. - Added support for the '-' date separator as well as the '/' separator. - Added support for languages other than English. Note that this support is not complete - error messages are still in English. The idea and German translation came from Wolfgang Thronicke. - Changed the -w option to include the "padding" and "spacing" options. NOTE INCOMPATIBILITY: In the previous patch level, creating a weekly calendar using the -c+n option left no blank lines between the day number and the first reminder entry. This has been changed so that one blank line is left. To revert to the old behaviour, use the "-w,,0" option. - Added the -o option to Rem2ps. This allows you to specify the margins when producing a PostScript calendar. - Updated the copyright notices in all the files. :-) - Added 'make clobber' and 'make test' targets to the Unix makefile. - Corrected typos in WHATSNEW.30 and remind.1 man page. Thanks to Dave Wolfe - Changed Remind so that supplying the -a option causes timed reminders not to be placed into the calendar in calendar mode. * Version 3.0 Patch 1 - 1992-12-18 - Wrote the Rem2ps program to produce PostScript calendars - Added an 'install' target to the Makefile - Fixed a bug which allowed the shell() function to execute in timed reminders which were queued with RUN disabled. - Added support for OS/2, courtesy of DARREL HANKERSON - In expressions, can now specify literal dates as 'yyyy/mm/dd' rather than using the date() function. - Fixed all the source files to include "config.h" first. - Changed the way triggers are calculated so that trigger dates are always valid if year, month and day are specified, and there is no UNTIL clause. See MAN page section "DETAILS ABOUT TRIGVALID()." - Defined _POSIX_SOURCE so Remind will compile on SGI workstations (and be more portable... I hope.) - Fixed some rather brain-dead definitions of UPPER and LOWER, as pointed out by - Added more details to the Man page concerning how triggers are computed, and added warnings about computing OMIT dates. - Added the file defs.rem which contains examples of useful definitions and triggers. - Changed the script test-rem to be a sh script instead of csh for improved portability. - Fixed up the README.* files to reflect the changes. - Re-formatted the WHATSNEW.30 file. * Version 3.0 - 1992-11-09 - Total rewrite from previous versions - Added variables, expressions, flow-control statements, daemon mode - Added "expression pasting" - Added CAL-type reminders - Added the SATISFY clause - Improved debugging of reminder scripts - Took out the "purge" option - it is in general too dificult to tell when a reminder has expired for good, so now it's up to you to do this by hand. - Fixed a lurking bug in trigger date calculation which, amazingly, had not been caught in the couple of years that Remind has been out! * Version 2.3 Patch 5 - 1992-04-11 - Added the "c+n" option for printing a calendar by weeks instead of months, courtesy Dennis Cottel (dennis@peanuts.nosc.mil). * Version 2.3 Patch 4 - 1991-11-06 - Made the init.c file nicer. Made the Makefile prettier. Added "make test", "make tar" and "make shar" Makefile targets. * Version 2.3 Patch 3 - 1991-09-11 - Added a command-line option for Remind to process queued reminders in the foreground. This makes automatic termination of Remind processes from within X-Windows and Sunview easier. * Version 2.3 Patch 2 - 1991-07-19 - Fixed up a problem with timed reminders which resulted in cursor not starting from left side of screen on some systems. - Fixed the SIGINT handler for SYSV systems - this was interrupting the sleep(2) system call. - Closed stdin and stdout if remind was part of a pipe - this prevents other sections of the pipe from hanging as remind puts itself in the background. - Added the "-h" (Hush mode) option - Added the "%#" and "%@" modifiers for the current time. - Made the Makefile more portable * Version 2.3 Patch 1 - 1991-03-08 - Added the "-t" command-line option to get Remind to trigger all non-expired reminders. - Added Turbo C support courtesy of Rhys Weatherly - Added the "RUN ON" and "RUN OFF" commands for a secure interface with the Elm mail system. - Added the "rem" shell script for running Remind with a default script. - Added manual pages for "kall" and "rem". * Version 2.3 - 1991-02-20 - Added the UNTIL keyword for forcing reminders to expire. - Added the "++" form of 'back' and the "--" form of 'delta' for ignoring OMIT information. - Added the CLEAR-OMIT-CONTEXT, PUSH-OMIT-CONTEXT and POP-OMIT-CONTEXT keywords for isolating personal or peculiar reminders from the global OMIT context. - Speeded up the parsing of tokens. - Changed the source to recognize and exploit ANSI-C compilers which accept function prototypes. - Added the "-n" option to output the next occurrence of each reminder in SimpleCalendar format - Modified the calendar and SimpleCalendar formats so that the % escape substitutions ARE performed. * Version 2.2 - Patch 5 - 1990-12-03 - Added the BEFORE, AFTER and SKIP tokens to make the handling of holidays more sensible. Also corrected a few more bugs. * Version 2.2 - Patch 3 - 1990-11-28 - Added the MSG or RUN tokens in an OMIT command; also allowed RUN-type reminders to be explicitly included in the calendar by using the %" escape sequence. * Version 2.2 - 1990-11-16 - Added the AT keyword, the timed reminders daemon, and the calendar facility. * Version 2.1 - 1990-11-06 - Added the "repeat" token for repeating reminders with a period other than 7 days. Also fixed some bugs from version 2.0 * Version 2.0 - 1990-11-01 - first public release. Included advanced date specifications, character substitution, and the RUN keyword. * Version 1.0 - never publicly released. remind-03.01.15/examples/defs.rem0000644000076400007640000005560012514120337014611 0ustar dfsdfs############################################################################# # # # DEFS.REM # # # # This file is a reminder script, which contains a few handy definitions. # # Cut and paste as desired! Also, near the end, there are a bunch of # # holiday definitions for the U.S. # # # # Some examples provided by George M. Sipe # # # # U.S. holidays provided by Dave Rickel # # # # Use your text editor to search for: # # "#USHOLS" for U.S. holidays # # "#JHOLS" for Jewish holidays # # "#PSSTUFF" for nifty PostScript examples # # "#COLORS" for examples of ANSI color escape sequences. # # # # This file is part of REMIND. # # Copyright (C) 1992-1997 Dianne Skoll # # Copyright (C) 1999-2000 Roaring Penguin Software Inc. # # # ############################################################################# RUN OFF ################################################ # Ensure required version of remind is used... # ################################################ IF version() < "03.01.08" ERRMSG This file requires at least version 03.01.08 of Remind.% ERRMSG This version is version [version()]. EXIT ENDIF ###################################### # Symbolic constants for weekdays... # ###################################### SET Sunday 0 SET Monday 1 SET Tuesday 2 SET Wednesday 3 SET Thursday 4 SET Friday 5 SET Saturday 6 SET Sun 0 SET Mon 1 SET Tue 2 SET Wed 3 SET Thu 4 SET Fri 5 SET Sat 6 ######################################### # Symbolic constants for month names... # ######################################### SET Jan 1 SET Feb 2 SET Mar 3 SET Apr 4 SET May 5 SET Jun 6 SET Jul 7 SET Aug 8 SET Sep 9 SET Oct 10 SET Nov 11 SET Dec 12 SET January 1 SET February 2 SET March 3 SET April 4 SET May 5 SET June 6 SET July 7 SET August 8 SET September 9 SET October 10 SET November 11 SET December 12 ########################################################### # Other symbolic constants and functions for "pasting"... # ########################################################### SET Quote CHAR(34) # Handy constants/function for specifing week of month... SET Week_1 1 SET Week_2 8 SET Week_3 15 SET Week_4 22 FSET _last(mo) "1 " + MON((mo%12)+1) + " --7" # Handy function to provide SCANFROM dates... FSET _back(days) TODAY()-days ########################################################### # Function which returns a string in "am/pm" format based # # on the time. For example, set a am_pm(NOW())... # ########################################################### FSET _am_pm(tm) IIF(tm<01:00, tm+12*60+"am", \ tm<12:00, tm+"am", \ tm<13:00, tm+"pm", \ tm-12*60+"pm") ################################################################# # Function which removes a single leading zero from a string... # ################################################################# FSET _no_lz(s) IIF(SUBSTR(s, 1, 1)=="0", SUBSTR(s, 2), s) ################################################################# # Return the length of the daylight/night portion of a date, # # in minutes. # ################################################################# FSET _light_len(date) MAX(SUNSET(date)-SUNRISE(date), 0) FSET _dark_len(date) 1440-_light_len(date) ############################################################ # Function to calculate number of years since a given year # # or number of months since a given month and year... # ############################################################ FSET _yr_num(yr) ORD(YEAR(TRIGDATE()) - yr) FSET _mo_num(mo, yr) ORD(12 * (YEAR(TRIGDATE()) - yr) + \ MONNUM(TRIGDATE()) - mo) # Here's an example of how to use them: REM 1 Nov ++12 MSG %"Dean's [_yr_num(1984)] birthday%" is %b. REM 1 MSG Dean's [_mo_num(11, 1984)] 'monthly' anniversary ########################################################### # Function to send mail via elm's "fastmail" (by GMS!)... # ########################################################### #FSET _mail(from, subj) "mailx -s " + \ # Quote + from + " : " + subj + Quote \ # GETENV("LOGNAME") + " < /dev/null 1>&0" FSET _mail(from, subj) "fastmail -f " + \ Quote + from + Quote + \ " -s " + Quote + subj + Quote + \ " /dev/null " + GETENV("LOGNAME") ############################################################################# # Here's a tricky problem: The 4th of July is a holiday in the U.S. # However, if it falls on a Saturday, the previous Friday is a holiday. # If it falls on a Sunday, the next Monday is a holiday. Here's how # to do it. NOTE that the following procedure makes the OMIT context # dependent upon the current date. SInce it only depends on the current # year, which is not likely to change while producing a calendar, we # are fairly safe. However, reminders with huge DELTA or BACK components # may not operate as expected. In general, any time you make OMIT # dependent upon the current date, it's tricky and results may not be # what you expect. You should try to make sure that the OMIT context # "near" any current reminders will not change during a calendar run. # The SCANFROM clause should help make these OMITs very safe. ############################################################################ # Calculate the weekday of the holiday. REM 4 July SCANFROM [_back(7)] SATISFY 1 IF WKDAYNUM(TRIGDATE()) == Sat REM [TRIGDATE()] MSG Independence day (actual) OMIT [TRIGDATE()-1] MSG Independence day (observed) ELSE IF WKDAYNUM(TRIGDATE()) == Sun REM [TRIGDATE()] MSG Independence day (actual) OMIT [TRIGDATE()+1] MSG Independence day (observed) ELSE OMIT [TRIGDATE()] MSG Independence day ENDIF ENDIF ############################################################################ # # # A meeting on the first Monday of every month which is moved to the # # second Monday in the event of a holiday. # # # ############################################################################ # First, the normal meeting. However, the SKIP keyword means this # one won't be triggered if the first Monday is a holiday REM Mon 1 SKIP MSG Meeting # Now, calculate the "potential" delayed meeting REM Mon 8 SATISFY 1 # But only actually trigger the delayed meeting if the previous # Monday was a holiday IF ISOMITTED(TRIGDATE()-7) REM [TRIGDATE()] MSG Delayed meeting ENDIF ############################################################################ # # # A very complicated reminder sent in by a Remind user. # # This person gets paid every two weeks, starting from 8 January 1993. # # If a pay date occurs before the twelfth of a month, then that # # he pays his mortgage on that pay date. Otherwise, he pays the mortgage # # on the previous pay date. Furthermore, he has to schedule his # # mortgage payment six days before it is due. He wants to be reminded # # a further four days before the scheduling deadline. He also # # wants to be mailed a notice two weeks before the scheduling deadline. # # # # Here's the solution - if you can follow this, consider yourself a # # Remind programmer extraordinaire! # # # ############################################################################ # A function to determine whether or not a pay-date is a mortgage-date. FSET _IsMortDate(x) DAY(x) < 12 || (DAY(x+14) >= 12 && DAY(x+14) <= 14) # Paydays - for reference REM 8 Jan 1993 *14 MSG Payday # Calculate the mortgage payment six days ahead of time. Note that this # is done "implicitly" by subtracting 6 from the starting date - we start # on 2 Jan rather than 8 Jan. We add 6 to TRIGDATE() in _IsMortDate to # compensate. REM 2 Jan 1993 *14 ++4 SATISFY [_IsMortDate(TRIGDATE()+6)] \ MSG %"Schedule mortgage payment%" for %a. # Now the mail reminder two weeks before the payment date - because two # weeks before a payment date is also a payment date, no pre-compensation # in the starting date of 8 Jan is necessary - convince yourself of this! # This uses the _mail() function defined earlier. REM ONCE 8 Jan 1993 *14 SATISFY [_IsMortDate(TRIGDATE()+14)] \ RUN [_mail("Decatur Federal", \ "Pay mortgage by the " + ORD(DAY(TRIGDATE()+14)))] # Make an entry on the calendar when the mortgage should be paid REM 8 Jan 1993 *14 SATISFY [_IsMortDate(TRIGDATE())] \ CAL Mortgage payment ########################################################################## # # # On our UNIX system, I run a program which queries the university # # library and creates a file called ".booksdue". This file is # # a REMIND script to tell me when my library books are due. Here's # # an example from my reminder file - it shows the use of filedate(). # # When the .booksdue file is at least 7 days old, I create a new version # # by querying the library computer. Note the use of realtoday() rather # # than today. # # # ########################################################################## IF !$RunOff && !$CalMode && !$SimpleCal IF REALTODAY()-FILEDATE("/home/dfs/.booksdue") >= 7 REM RUN /home/dfs/bilge/library/getbooks ENDIF ENDIF #PSSTUFF1 ########################################################################## # # # This portion of the file contains some cute examples of the new # # PS-type reminders. You need a PostScript printer or viewer to # # appreciate these. To use them, pipe the output of remind -p into the # # rem2ps program. More examples are in the PSSTUFF2 section, below. # # # ########################################################################## # The following reminder will shade the Saturday and Sunday calendar # entries. REM Sat Sun SPECIAL SHADE 220 #USHOLS ############################################################################# # # # The following holidays were provided by Dave Rickel # # Modified by D. Skoll to give safe OMITs for moveable holidays # # # ############################################################################# SET SaveTrig $NumTrig SET easter EASTERDATE(YEAR(TODAY())) REM [easter-46] MSG %"Ash Wednesday%" REM [easter-7] MSG %"Palm Sunday%" OMIT [easter-2] MSG %"Good Friday%" OMIT [easter] MSG %"Easter%" Sunday REM [easter+39] MSG %"Ascension Day%" REM [easter+49] MSG %"Pentecost%" # Some holidays are omitted, some are not. You may want to change # which ones are omitted - use the general forms shown below. # You'll need the _back() function and the Week_n variables defined # way up in the file. OMIT Jan 1 MSG %"New Year's%" Day REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%" REM Feb 2 MSG %"Ground Hog Day%" REM Feb 14 MSG %"Valentine's%" Day REM Mon Feb [Week_3] SCANFROM [_back(7)] SATISFY 1 OMIT [trigdate()] MSG %"President's Day%" REM Mar 17 MSG %"St. Patrick's%" Day # The DST rules are accurate for most locations in # North America REM Sun Apr 1 ++2 UNTIL 1 Jan 2007 MSG Daylight Saving Time - %"DST starts%" %b REM Sun Mar 8 ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST starts%" %b REM Apr 1 MSG %"April Fool's%" Day REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due REM May 5 MSG %"Cinco de Mayo%" REM Sat May [Week_1] MSG %"Kentucky Derby%" REM Sun May [Week_2] MSG %"Mother's Day%" REM Sat May [Week_3] MSG %"Armed Forces Day%" REM Mon [_last(May)] SCANFROM [_back(7)] SATISFY 1 OMIT [trigdate()] MSG %"Memorial Day%" REM Jun 14 MSG %"Flag Day%" REM Sun Jun [Week_3] MSG %"Father's Day%" REM Mon Sep [Week_1] SCANFROM [_back(7)] SATISFY 1 OMIT [trigdate()] MSG %"Labor Day%" REM Mon Oct [Week_2] MSG %"Columbus Day%" REM Nov 11 MSG %"Veterans Day%" # The DST rules are accurate for most locations in # North America REM Sun [_last(Oct)] UNTIL 1 Jan 2007 MSG Daylight Saving Time - %"DST over%" REM Sun 1 Nov FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST over%" REM Oct 30 MSG %"Mischief Night%" REM Oct 31 MSG %"Halloween%" REM Tue Nov 2 SCANFROM [_back(7)] \ SATISFY [(YEAR(TRIGDATE()) % 4) == 0] \ MSG %"Election%" Day REM Thu Nov [Week_4] SCANFROM [_back(7)] SATISFY 1 OMIT [trigdate()] MSG %"Thanksgiving%" Day REM Fri Nov [Week_4+1] SCANFROM [_back(7)] SATISFY 1 OMIT [trigdate()] MSG %"Thanksgiving%" (cont.) OMIT Dec 24 MSG %"Christmas Eve%" OMIT Dec 25 MSG %"Christmas%" Day ########################################################################## # # # If any US holidays were triggered above, shade in the calendar # # entry in PostScript. This is not quite correct, as it blots out any # # other PostScript stuff above. I was too lazy to do it properly :-) # # # ########################################################################## if $NumTrig > SaveTrig REM SPECIAL SHADE 220 endif # Seasons (valid from 1992 to 2000)... REM Mar 20 MSG %"Spring%" begins REM Jun [IIF(YEAR(TODAY())%4, 21, 20)] MSG %"Summer%" begins REM Sep [CHOOSE(YEAR(TODAY())-1991, 22,22,23,23,22,22,22,23,22)] \ MSG %"Fall%" begins REM Dec [IIF((YEAR(TODAY())+1)%4, 21, 22)] MSG %"Winter%" begins #PSSTUFF2 ########################################################################## # # # Since the SHADE special blots out any previous PostScript # # reminders for a date, these examples need to follow the US Holidays # # section, which uses SHADE. # # # ########################################################################## # The following will fill in the Hebrew dates on the calendar. For this # example, I recommend that you use the -sd 10 option for Rem2PS. REM PS Border Border moveto \ /DayFont findfont DaySize scalefont setfont \ ([hebday(today())] [hebmon(today())]) show # Fill in the phases of the moon on the PostScript calendar [moondate(0)] SPECIAL MOON 0 [moondate(1)] SPECIAL MOON 1 [moondate(2)] SPECIAL MOON 2 [moondate(3)] SPECIAL MOON 3 # The following example puts sunrise and sunset times in PostScript in the # calendar - the sizes are hard-coded, however, and work best in landscape. REM PS Border Border 5 sub moveto \ /SmallFont findfont 4 scalefont setfont \ (Sunrise: [sunrise(trigdate())] Sunset: [sunset(trigdate())]) show # The next one puts the day number (1-366) and days left in the year at the # bottom of the post-script calendar. Again, the hard-coded sizes work best # in landscape. FSET _DayOfYear(x) x-(date(year(x),1,1) - 1) REM PS BoxWidth 3 mul 4 div Border 5 sub moveto \ /SmallFont findfont 4 scalefont setfont \ ([_DayOfYear(today())]([365+isleap(today())-_DayOfYear(today())])) show #JHOLS ########################################################################## # # # This portion of the file contains reminders for Jewish holidays. The # # dates were obtained from "The First Jewish Catalog" by Richard Siegel # # and Michael and Sharon Strassfeld, published by the Jewish Publication # # Society of America. The Reform version of the calendar was guessed # # at by Dianne Skoll based on experience. There is probably no standard # # Reform position on many of the holidays, so you may have to adjust # # the file as required. # # # # Additional corrections were made from the paper "Calendrical # # Calculations" by Nachum Dershowitz and Edward M. Reingold. Any # # further corrections are welcome. # # # ########################################################################## # Here are some general functions that you might find nice to use # _hstr: Returns a string which is the full Hebrew date of its argument. # Example: hstr('1994/02/02') returns "21 Shvat 5754" FSET _hstr(x) HEBDAY(x) + " " + HEBMON(x) + " " + HEBYEAR(x) # _hyrlen: Return the length of the specified Hebrew year # Example: _hyrlen(5754) returns 355 FSET _hyrlen(x) HEBDATE(1, "Tishrey", x+1) - HEBDATE(1, "Tishrey", x) # --- HERE ARE THE JEWISH HOLIDAYS --- # Set the variable InIsrael to 1 if you live in Israel. Otherwise, # you get the Diaspora versions of Jewish holidays SET InIsrael 0 # Set the variable Reform to 1 if you want the Reform version of the # Jewish calendar. Otherwise, you get the traditional version SET Reform 0 # Convenient function definition to save typing FSET _h(x, y) HEBDATE(x,y) FSET _h2(x, y) HEBDATE(x, y, TODAY()-7) FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)+1) FSET _PastSun(x, y) IIF(WKDAYNUM(_h2(x,y))!=0, _h2(x,y), _h2(x,y)+1) FSET _PastMon(x, y) IIF(WKDAYNUM(_h2(x,y))!=1, _h2(x,y), _h2(x,y)+1) # Default values in case InIsrael and Reform are not set SET InIsrael VALUE("InIsrael", 0) SET Reform VALUE("Reform", 0) [_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b. # No RH-2 or Tzom Gedalia in Reform IF !Reform [_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b. [_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b. ENDIF [_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b. [_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b. IF !InIsrael [_h(16, "Tishrey")] MSG %"Sukkot 2%" ENDIF [_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b. [_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b. IF InIsrael [_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b. ELSE [_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b. ENDIF # Because Kislev can change length, we must be more careful about Chanukah FSET _chan(x) HEBDATE(24, "Kislev", today()-9)+x [_chan(1)] ++4 MSG %"Chanukah 1%" is %b. [_chan(2)] MSG %"Chanukah 2%" [_chan(3)] MSG %"Chanukah 3%" [_chan(4)] MSG %"Chanukah 4%" [_chan(5)] MSG %"Chanukah 5%" [_chan(6)] MSG %"Chanukah 6%" [_chan(7)] MSG %"Chanukah 7%" [_chan(8)] MSG %"Chanukah 8%" # Not sure about Reform's position on the next one. IF !Reform # 10 Tevet will never be a Saturday, so whether or not to # move it is moot. (Thanks to Art Werschulz.) [_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b. ENDIF [_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b. [_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b. [_h(15, "Adar A")] ++4 MSG %"Shushan Purim Katan%" is %b. # If Purim is on Sunday, then Fast of Esther is 11 Adar. IF WKDAYNUM(_h2(13, "Adar")) != 6 REM [_h2(13, "Adar")] ++4 MSG %"Fast of Esther%" is %b. ELSE REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b. ENDIF [_h(14, "Adar")] ++4 MSG %"Purim%" is %b. [_h(15, "Adar")] ++4 MSG %"Shushan Purim%" is %b. [_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b. IF !InIsrael [_h(16, "Nisan")] MSG %"Pesach 2%" ENDIF [_h(21, "Nisan")] MSG %"Pesach 7%" IF !InIsrael && !Reform [_h(22, "Nisan")] MSG %"Pesach 8%" ENDIF REM [_PastSun(27, "Nisan")] SATISFY 1 IF $Tw == 5 REM [_PastSun(26, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b. ELSE REM [_PastSun(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b. ENDIF # If 4 Iyar is a Friday, then Yom Hazikaron is # the Wednesday before and Yom Ha'atzmaut is on # Thursday. If 4 Iyar is a Sunday, then Yom Hazikaron # moves to 5 Iyar and Yom Ha'atzmaut to 6 Iyar. IF WKDAYNUM(_h2(4, "Iyar")) == 5 [_h(2, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b. [_h(3, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b. ELSE IF WKDAYNUM(_h2(4, "Iyar")) == 0 [_h(5, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b. [_h(6, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b. ELSE [_h(4, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b. [_h(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b. ENDIF ENDIF # Not sure about Reform's position on Lag B'Omer IF !Reform [_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b. ENDIF [_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b. [_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b. IF !InIsrael && !Reform [_h(7, "Sivan")] MSG %"Shavuot 2%" ENDIF # Fairly sure Reform Jews don't observe the next two IF !Reform # Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally # fall on a Saturday [_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b. [_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b. ENDIF # Counting the omer - do the whole spiel, i.e: # "This is the xth day of the omer, being y weeks and z days of the omer." # Nice Remind programming example here! SET ostart HEBDATE(16, "Nisan", TODAY()-50) IF ostart <= TODAY() && (TODAY() - ostart < 49) SET odays TODAY()-ostart+1 IF odays < 7 MSG %"%"Today is the [ORD(odays)] day of the Omer. ELSE IF !(odays % 7) MSG %"%"Today is the [ORD(odays)] day of the Omer, being [odays / 7] [PLURAL(odays/7, "week")] of the Omer. ELSE MSG %"%"Today is the [ORD(odays)] day of the Omer, being [odays/7] [PLURAL(odays/7, "week")] and [odays%7] [PLURAL(odays%7, "day")] of the Omer. ENDIF ENDIF CAL [ORD(odays)] of Omer ENDIF ### Candle lighting and Havdalah. You should probably add candle lighting ### for other holidays besides Shabbat. These just create calendar entries ### for Friday and Saturday. Note: You must set your latitude, longitude ### and possibly time zone for these to work properly! REM Friday CAL Candle lighting at [sunset(trigdate())-18] REM Saturday CAL Havdalah at [sunset(trigdate())+42] #COLORS ########################################################################## # # # This contains sample ANSI escape sequences for coloring messages. # # It should work on an IBM PC with the ANSI.SYS driver, and on # # other terminals which use the ANSI sequences. # # # # This information was provided by Gail Gurman. # # ########################################################################## # Colors - use Nrm to reset to normal text. SET Esc CHAR(27) SET Nrm Esc + "[0m" SET Blk Esc + "[0;30m" SET Red Esc + "[0;31m" SET Grn Esc + "[0;32m" SET Ylw Esc + "[0;33m" SET Blu Esc + "[0;34m" SET Mag Esc + "[0;35m" SET Cyn Esc + "[0;36m" SET Wht Esc + "[0;37m" SET Gry Esc + "[30;1m" SET BrRed Esc + "[31;1m" SET BrGrn Esc + "[32;1m" SET BrYlw Esc + "[33;1m" SET BrBlu Esc + "[34;1m" SET BrMag Esc + "[35;1m" SET BrCyn Esc + "[36;1m" SET BrWht Esc + "[37;1m" # Examples REM MSG A [Blu]blue[Nrm] reminder. REM MSG [Red]%"A red reminder%" safe to use in the calendar mode.[Nrm] # Here is an example of how to use msgprefix() and msgsuffix(). These # will highlight priority-0 reminders in bright red, # priority-2500 in red, and priority-7500 in blue. All others # will be in the normal colors FSET msgprefix(x) iif(x==0, BrRed, x==2500, Red, x==7500, Blu, Nrm) # Don't forget to return to normal color set at the end of reminder! FSET msgsuffix(x) Nrm # The next examples are great for putting right at the end of the reminder # file. They make queued reminders more eye-catching when they pop up. FSET msgprefix(x) char(13,10,13,10)+"******************"+char(13,10,13,10) FSET msgsuffix(x) char(13,10)+"******************"+char(13,10,13,10) remind-03.01.15/examples/remind.vim0000644000076400007640000000535011667240325015163 0ustar dfsdfs" Vim syntax file " Language: Remind " Maintainer: Davide Alberani " Last Change: 18 Sep 2009 " Version: 0.5 " URL: http://erlug.linux.it/~da/vim/syntax/remind.vim " " remind is a sophisticated reminder service " you can download remind from: " http://www.roaringpenguin.com/penguin/open_source_remind.php if version < 600 syntax clear elseif exists("b:current_syntax") finish endif " shut case off. syn case ignore syn keyword remindCommands REM OMIT SET FSET UNSET syn keyword remindExpiry UNTIL FROM SCANFROM SCAN WARN SCHED THROUGH syn keyword remindTag PRIORITY TAG syn keyword remindTimed AT DURATION syn keyword remindMove ONCE SKIP BEFORE AFTER syn keyword remindSpecial INCLUDE INC BANNER PUSH-OMIT-CONTEXT PUSH CLEAR-OMIT-CONTEXT CLEAR POP-OMIT-CONTEXT POP COLOR COLOUR syn keyword remindRun MSG MSF RUN CAL SATISFY SPECIAL PS PSFILE SHADE MOON syn keyword remindConditional IF ELSE ENDIF IFTRIG syn keyword remindDebug DEBUG DUMPVARS DUMP ERRMSG FLUSH PRESERVE syn match remindComment "#.*$" syn region remindString start=+'+ end=+'+ skip=+\\\\\|\\'+ oneline syn region remindString start=+"+ end=+"+ skip=+\\\\\|\\"+ oneline syn match remindVar "\$[_a-zA-Z][_a-zA-Z0-9]*" syn match remindSubst "%[^ ]" syn match remindAdvanceNumber "\(\*\|+\|-\|++\|--\)[0-9]\+" " XXX: use different separators for dates and times? syn match remindDateSeparators "[/:@\.-]" contained syn match remindTimes "[0-9]\{1,2}[:\.][0-9]\{1,2}" contains=remindDateSeparators " XXX: why not match only valid dates? Ok, checking for 'Feb the 30' would " be impossible, but at least check for valid months and times. syn match remindDates "'[0-9]\{4}[/-][0-9]\{1,2}[/-][0-9]\{1,2}\(@[0-9]\{1,2}[:\.][0-9]\{1,2}\)\?'" contains=remindDateSeparators " This will match trailing whitespaces that seem to break rem2ps. " Courtesy of Michael Dunn. syn match remindWarning display excludenl "\S\s\+$"ms=s+1 if version >= 508 || !exists("did_remind_syn_inits") if version < 508 let did_remind_syn_inits = 1 command -nargs=+ HiLink hi link else command -nargs=+ HiLink hi def link endif HiLink remindCommands Function HiLink remindExpiry Repeat HiLink remindTag Label HiLink remindTimed Statement HiLink remindMove Statement HiLink remindSpecial Include HiLink remindRun Function HiLink remindConditional Conditional HiLink remindComment Comment HiLink remindTimes String HiLink remindString String HiLink remindDebug Debug HiLink remindVar Identifier HiLink remindSubst Constant HiLink remindAdvanceNumber Number HiLink remindDateSeparators Comment HiLink remindDates String HiLink remindWarning Error delcommand HiLink endif let b:current_syntax = "remind" " vim: ts=8 sw=2 remind-03.01.15/install-sh0000755000076400007640000001124511057403122013343 0ustar dfsdfs#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 remind-03.01.15/man/cm2rem.10000644000076400007640000000202612514120337013361 0ustar dfsdfs.TH CM2REM 1 "18 October 1999" .UC 4 .SH NAME cm2rem.tcl \- Convert Sun's "cm" input file to Remind format .SH SYNOPSIS .B cm2rem.tcl < cm_file > remind_file .SH DESCRIPTION \fBcm2rem.tcl\fR reads the Sun calendar manager data file and converts it into a \fBRemind\fR script. Note that \fBcm2rem.tcl\fR can convert \fIonly\fR version 3 calendar manager files. If you are using version 4 files, there should be a system utility to convert them to version 3 files. .SH AUTHOR \fBcm2rem.tcl\fR is supported by Roaring Penguin Software Inc. (http://www.roaringpenguin.com) .PP \fBcm2rem.tcl\fR was written by Dianne Skoll . .SH BUGS Not all of the Sun calendar manager options are respected. In particular, nothing is done for e-mail actions. Also, the resulting Remind script is not editable with \fBTkRemind\fR; you can only edit it with a text editor. .PP \fBcm2rem.tcl\fR requires Tcl/Tk version 8.0 or higher. The \fBtclsh\fR interpreter must be on your \fBpath\fR. .SH SEE ALSO \fBremind(1)\fR, \fBtkremind(1)\fR remind-03.01.15/man/rem.10000644000076400007640000000123012514120337012753 0ustar dfsdfs.TH REM 1 "30 August 2007" .UC 4 .SH NAME rem \- Invoke Remind with a default filename .SH SYNOPSIS .B rem [\fIoptions\fR] [\fIdate\fR] [\fI*rep\fR] [\fItime\fR] .SH DESCRIPTION \fBrem\fR is a symbolic link to \fBremind\fR. When \fBremind\fR determines that it has been invoked as \fBrem\fR, it uses a default filename rather than expecting a filename to be supplied on the command line. .PP If the environment variable DOTREMINDERS is set, \fBremind\fR uses the value of DOTREMINDERS as the filename. Otherwise, \fBremind\fR uses the filename $HOME/.reminders .PP .SH AUTHOR Remind was written by Dianne Skoll .SH SEE ALSO \fBremind\fR remind-03.01.15/man/rem2ps.10000644000076400007640000003241612514120337013412 0ustar dfsdfs.TH REM2PS 1 "11 April 2005" .UC 4 .SH NAME rem2ps \- draw a PostScript calendar from Remind output .SH SYNOPSIS .B rem2ps [\fIoptions\fR] .SH DESCRIPTION \fBRem2ps\fR reads the standard input, which should be the results of running \fBRemind\fR with the \fB\-p\fR option. It emits PostScript code (which draws a calendar) to the standard output. .PP See the section "Rem2PS Input Format" for details about the \fB\-p\fR data. This may be useful if you wish to create other \fBRemind\fR back-ends. .SH OPTIONS .TP .B \-v Be more verbose. This causes \fBRem2ps\fR to print progress messages to the standard error stream. Normally, it is silent. .TP .B \-p file Include the contents of \fIfile\fR in the PostScript prologue. This allows you to define procedures, variables etc. which can be used by the \fBPS\fR and \fBPSFILE\fR reminders. You should not include any document structuring comments in your prologue. .TP .B \-l Produce the calendar in landscape mode rather than the default portrait mode. .TP \fB\-c\fR[\fIn\fR] If \fIn\fR is omitted, disables the small calendars for next and previous months which are normally generated. If \fIn\fR is supplied, it can range from 0 to 3, with the following meanings: .RS .TP .B 0 Disable small calendars .TP .B 1 Place the small calendars at the bottom-right if there is room; otherwise, place them at the top-left. .TP .B 2 Place the small calendars at the top-left if there is room; otherwise, place them at the bottom-right. .TP .B 3 Place the previous month's small calendar at the top-left and the next month's at the bottom-right if there is room; otherwise, follow \fIn\fR=1. A moment's thought reveals that an option which splits the calendars if there is room and otherwise follows \fIn\fR=2 yields the same results as \fIn\fR=3. .RE .TP .B \-i Use ISO 8859-1 standard encoding for the PostScript fonts. If you do not use this option, the default encoding is used. .TP .B \-e Make the calendar fill the entire page. By default, the calendar is slightly smaller than the page. This allows days with many reminders to "expand" as needed. However, if you don't have days which expand, you can use this option to make all of the boxes slightly bigger. One caveat: If you do use the \fB\-e\fR option and one day has many reminders, the calendar may expand off the page, losing some information. Experiment! .TP .B \-m media Set the page size. If you use the \-m option, you must specify the media type, which can be one of the following. (Sizes are approximate.) .RS .TP Letter 8.5 x 11 in. .TP Legal 8.5 x 14 in. .TP Ledger 11 x 17 in. .TP Statement 5.5 x 8.5 in. .TP Executive 7.5 x 10 in. .TP A3 29.7 x 42 cm. .TP A4 21 x 29.7 cm. .TP A5 14.8 x 21 cm. .TP B4 25.7 x 36.4 cm. .TP B5 18.3 x 25.7 cm. .TP Folio 8.5 x 13 in. .TP Quarto 8.5 x 10.8 in. .TP 10x14 10 x 14 in. .TP \fIX\fRx\fIY\fRin \fIX\fR by \fIY\fR inches, where \fIX\fR and \fIY\fR can be floating-point numbers. .TP \fIX\fRx\fIY\fRcm \fIX\fR by \fIY\fR centimetres, where \fIX\fR and \fIY\fR can be floating-point numbers. .PP Type "rem2ps \-m help" for a list of available media. Note that the media type (and all \fBRem2ps\fR options) are case-sensitive. If you don't use the \fB\-m\fR option, the media defaults to a compiled-in default - this is usually Letter for North America and A4 for Europe. The "\-m help" option will display the compiled-in default. .RE .TP \fB\-f\fR[\fBtshed\fR] \fIfont\fR Set the font for the calendar title, the small calendars, the day-of-week headings, the calendar entries, and the day numbers, respectively. \fIFont\fR must be the name of a valid PostScript font. The default fonts are equivalent to specifying: .RS .PP .nf \-ftshe Helvetica \-fd Helvetica-BoldOblique .fi .PP In other words, the heading, entry and small-calendar fonts are set to Helvetica, and the font for the day numbers is set to Helvetica-BoldOblique. .RE .TP \fB\-s\fR[\fBthed\fR] \fIsize\fR Set the size (in points) of the text for the the calendar title, day-of-week headings, the calendar entries, and the day numbers, respectively. \fISize\fR must be a decimal number. The default sizes are equivalent to specifying: .RS .PP .nf \-sthd 14 \-se 8 .fi .PP In other words, the heading and day numbers are 14-point fonts, and the calendar entries are printed in 8-point text. .RE .TP \fB\-b\fR \fIsize\fR Set the size of the blank white border in each calendar box to \fIsize\fR points. The default border size is 6 points, or 1/12 in. .TP \fB\-t\fR \fIsize\fR Set the thickness of the black calendar grid lines. The default is 1, for a line thickness of one point (1/72 in.) .TP \fB\-o\fR[\fBlrtb\fR] \fIsize\fR Set the left, right, top, and/or bottom margins to \fIsize\fR points. For this option only, \fIsize\fR must be an integer. It represents the margin size in units of 1/72 in. The default margin sizes are 36, for half-inch margins. If you wish to punch holes in the calendar page to insert it into a binder, you may wish to increase the left margin to one inch. In that case, you should also decrease the heading font size to 12 points for good output: .PP .nf # This gives good results for putting into a binder rem2ps \-ol 72 \-sh 12 .fi .SH USAGE To use \fBRem2ps\fR, you should pipe the output of \fBRemind\fR with the \fB\-p\fR option to \fBRem2ps\fR, and then send the result to a printer. This is most easily illustrated with examples: .PP .nf remind \-p12 /dev/null 1 jan 1994 | rem2ps | lpr \-Plaser .fi .PP That example creates a blank calendar for the entire year of 1994, and sends it the the printer named "laser." .PP .nf remind \-p ~/.reminders | rem2ps \-l \-sd 18 > cal.ps .fi .PP This reminder creates a calendar for the current month, filling in entries from the reminder file "~/.reminders." The calendar is produced in landscape mode, with a font size of 18 for the day numbers. The result is put in the PostScript file "cal.ps." .PP .SH VARIABLES AVAILABLE TO USER-SUPPLIED POSTSCRIPT CODE .PP The following variables are available to \fBPS\fR and \fBPSFILE\fR-type reminders. (This material is duplicated in the \fBRemind\fR manual page.) .TP LineWidth The width of the black grid lines making up the calendar. .TP Border The border between the center of the grid lines and the space used to print calendar entries. This border is normally blank space. .TP BoxWidth and BoxHeight The width and height of the calendar box, from center-to-center of the black gridlines. .TP InBoxHeight The height from the center of the bottom black gridline to the top of the regular calendar entry area. The space from here to the top of the box is used only to draw the day number. .TP /DayFont, /TitleFont, /EntryFont, /SmallFont and /HeadFont The fonts used to draw the day numbers, the month and year title, the calendar entries, the small calendars, and the day-of-week headings, respectively. .TP DaySize, TitleSize, EntrySize and HeadSize The sizes of the above fonts. (The size of the small calendar font is \fInot\fR defined here.) For example, if you wanted to print the Hebrew date next to the regular day number in the calendar, use: .PP .nf REM PS Border BoxHeight Border sub DaySize sub moveto \\ /DayFont findfont DaySize scalefont setfont \\ ([hebday(today())] [hebmon(today())]) show .fi .PP .RS Note how /DayFont and DaySize are used. .RE .PP Note that if you supply PostScript code, it is possible to produce invalid PostScript files. Always test your PostScript thoroughly with a PostScript viewer before sending it to the printer. You should not use any document structuring comments in your PostScript code. .PP In addition, prior to drawing a calendar page, \fBRem2ps\fR emits the following PostScript code: .PP .nf save (mon) (yr) PreCal restore .fi .PP where \fImon\fR and \fIyr\fR are the month and year of the calendar page. The default \fBPreCal\fR procedure simply pops the arguments and does nothing. However, you can define a \fBPreCal\fR function in your prologue file to do whatever you want - it can draw a background for the entire calendar, for instance. .PP In the context of the \fBPreCal\fR procedure, the following conditions hold: .TP o The PostScript origin is at the bottom left-hand corner of the page, and PostScript units of 1/72" are in effect. .TP o The variables MinX, MinY, MaxX and MaxY define the bounding box within which the calendar will be drawn. .TP o The font and font-size variables, as well as Border and LineWidth described previously, are valid. .PP For an example, create a file called "myprolog" whose contents are: .PP .nf /PreCal { /yr exch def /mon exch def /xsiz1 MaxX MinX sub def /ysiz1 MaxY MinY sub def /xsiz xsiz1 MinX sub MinX sub def /ysiz ysiz1 MinY sub MinY sub def xsiz ysiz lt {/len xsiz 1.41 mul def MinX MinX add ysiz1 xsiz1 sub 2 div MinY add MinY add moveto} {/len ysiz 1.41 mul def xsiz1 ysiz1 sub 2 div MinX add MinX add MinY MinY add moveto} ifelse /Helvetica-Bold findfont 1 scalefont setfont mon stringwidth pop ( ) stringwidth pop add yr stringwidth pop add len exch div /len exch def /Helvetica-Bold findfont len scalefont setfont 0.95 setgray 45 rotate mon show ( ) show yr show } bind def .fi .PP Use that file with the \fBRem2ps\fR \fB\-p\fR option to create calendars with the year and month in large grey letters in the background of the calendar. .PP .SH REM2PS INPUT FORMAT \fBRemind \-p\fR sends the following lines to standard output. The information is designed to be easily parsed by back-end programs: .TP .B # rem2ps begin This line signifies the start of calendar data. Back-ends can search for it to verify they are being fed correct information. .TP \fImonth_name year num_days first_day monday_first\fR On this line, \fImonth_name\fR is the name of the month whose calendar information is about to follow. \fInum_days\fR is the number of days in this month. \fIfirst_day\fR is the weekday of the first day of the month (0 = Sunday, 1 = Monday, 6 = Saturday.) And \fImonday_first\fR is 1 if the \fB\-m\fR flag was supplied to \fBRemind\fR, or 0 if it was not. All this information is supplied so back-ends don't need any date calculation facilities. .TP \fIsun mon tue wed thu fri sat\fR This line consists of space-separated names of days in whatever language \fBRemind\fR was compiled for. This information can be used by back-ends to annotate calendars, and means they don't have to be created for a specific language. .TP \fInext_mon next_days\fR The name of the next month and the number of days in it. .TP \fIprev_mon prev_days\fR The name of the previous month and the number of days in it. The \fInext_mon\fR and \fIprev_mon\fR lines could be used to generate small inset calendars for the next and previous months. .PP The remaining data consists of calendar entries, in the following format: .PP \fIyyyy/mm/dd special tag dur time body\fR .PP Here, \fIyyyy\fR is the year, \fImm\fR is the month (01-12) and \fIdd\fR is the day of the month. Note that the date components are always separated by "/" even if the date separator in \fBRemind\fR has been set to "-". The consistent use of "/" is designed to ease parsing. .PP \fIspecial\fR is a string used for "out-of-band" communication with back-ends. If the reminder is a normal reminder, \fIspecial\fR is "*". The \fBRem2PS\fR back-end understands the specials \fBPostScript\fR and \fBPSFile\fR. Other back-ends may understand other specials. A back end should \fIsilently ignore\fR a reminder with a special it doesn't understand. .PP \fItag\fR is whatever tag the user provided with the \fBTAG\fR clause, or "*" if no tag was provided. If there is more than one \fBTAG\fR clause, the tags appear in a comma-separated list. For example, the command \fBREM TAG foo TAG bar TAG quux\fR would result in \fBfoo,bar,quux\fR in the \fItag\fR field. .PP \fIdur\fR is the \fBDURATION\fR value in minutes, or "*" if no duration was provided. .PP \fItime\fR is the time of the reminder in minutes past midnight, or "*" if the reminder was not a timed reminder. .PP \fIbody\fR is the body of the reminder. .PP After a month's worth of reminders have been emitted, \fBRemind\fR emits the line: .PP \fB# rem2ps end .PP However, back-ends should keep reading until EOF in case more data for subsequent months is forthcoming. .PP If you supply the \fB\-l\fR option to \fBremind\fR, then reminders may be preceded by a line that looks like this: .PP \fB# fileinfo \fIlineno filename\fR .PP The word \fBfileinfo\fR is literal; \fIlineno\fR and \fIfilename\fR specify the line number and file name of the file containing the reminder. Back-ends that don't care about this information should ignore lines starting with "#" (except, of course, for the # rem2ps lines.) .PP .SH AUTHOR Rem2PS is now supported by Roaring Penguin Software Inc. (http://www.roaringpenguin.com) .PP Rem2PS was written by Dianne Skoll . .SH BUGS All \fBRem2ps\fR options are case-sensitive, unlike \fBRemind\fR. Any time you supply a font name or size, line thickness, or border width, it is treated as a string and sent straight to the PostScript interpreter. Thus, if you supply invalid fonts or sizes, \fBRem2ps\fR will not complain, but the resulting PostScript output will probably not work. .PP You should ensure that the values you supply for margin widths are sensible. If they are too big for the media size, \fBRem2ps\fR will not complain, but again, the PostScript output will probably not work. .SH SEE ALSO \fBremind\fR remind-03.01.15/man/remind.10000644000076400007640000047150012516507152013467 0ustar dfsdfs.TH REMIND 1 "31 August 2008" .UC 4 .SH NAME remind \- a sophisticated reminder service .SH SYNOPSIS .B remind [\fIoptions\fR] \fIfilename\fR [\fIdate\fR] [\fI*rep\fR] [\fItime\fR] .SH DESCRIPTION \fBRemind\fR reads the supplied \fIfilename\fR and executes the commands found in it. The commands are used to issue reminders and alarms. Each reminder or alarm can consist of a message sent to standard output, or a program to be executed. .PP If \fIfilename\fR is specified as a single dash '-', then \fBRemind\fR takes its input from standard input. This also implicitly enables the \fB\-o\fR option, described below. .PP If \fIfilename\fR happens to be a directory rather than a plain file, then \fBRemind\fR reads all of the files in that directory that match the pattern "*.rem". The files are read in sorted order; the sort order may depend on your locale, but should match the sort order used by the shell to expand "*.rem". .PP \fBRemind\fR reads its files starting from the beginning to the end, or until it encounters a line whose sole content is "__EOF__" (without the quotes.) Anything after the __EOF__ marker is completely ignored. .SH OPTIONS \fBRemind\fR has a slew of options. If you're new to the program, ignore them for now and skip to the section "Reminder Files". .TP .B \-n The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence of each reminder in a simple calendar format. You can sort this by date by piping the output through \fBsort(1)\fR. .TP .B \-j\fR[\fIn\fR] Runs \fBRemind\fR in "purge" mode to get rid of expired reminders. See the section PURGE MODE for details. .TP .B \-r The \fB\-r\fR option disables \fBRUN\fR directives and the \fBshell()\fR function. As of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR. .TP .B \-c\fI[flags]\fIn\fR The \fB\-c\fR option causes \fBRemind\fR to produce a calendar that is sent to standard output. If you supply a number \fIn\fR, then a calendar will be generated for \fIn\fR months, starting with the current month. By default, a calendar for only the current month is produced. .PP You can precede \fIn\fR (if any) with a set of flags. The flags are as follows: .TP .B '+' causes a calendar for \fIn\fR weeks to be produced. .TP .B 'a' causes \fBRemind\fR to display reminders on the calendar on the day they actually occur \fIas well as\fR on any preceding days specified by the reminder's \fIdelta\fR. .TP .B 'l' causes \fBRemind\fR to use VT100 line-drawing characters to draw the calendar. The characters are hard-coded and will only work on terminals that emulate the VT00 line-drawing character set. .TP .B 'u' is similar to 'l', but causes \fBRemind\fR to use UNICODE line-drawing characters to draw the calendar. The characters are hard-coded and will only work on terminals that are set to UTF-8 character encoding. .TP .B 'c' causes \fBRemind\fR to use VT100 escape sequences to approximate SPECIAL COLOR reminders. The approximation is (of necessity) very coarse, because the VT100 only has eight different color sequences, each with one of two brightnesses. A color component greater than 64 is considered "on", and if any of the three color components is greater than 128, the color is considered "bright". .TP .B \-w\fR\fIcol\fR[,\fIpad\fR[,\fIspc\fR]]] The \fB\-w\fR option specifies the output width, padding and spacing of the formatted calendar output. \fICol\fR specifies the number of columns in the output device, and defaults to 80. \fIPad\fR specifies how many lines to use to "pad" empty calendar boxes. This defaults to 5. If you have many reminders on certain days that make your calendar too large to fit on a page, you can try reducing \fIpad\fR to make the empty boxes smaller. \fISpc\fR specifies how many blank lines to leave between the day number and the first reminder entry. It defaults to 1. .RS .PP Any of \fIcol\fR, \fIpad\fR or \fIspc\fR can be omitted, providing you provide the correct number of commas. Don't use any spaces in the option. .RE .TP .B \-s\fR[\fBa\fR]\fIn\fR The \fB\-s\fR option is very similar to the \fB\-c\fR option, except that the output calendar is not formatted. It is listed in a "simple format" that can be used as input for more sophisticated calendar-drawing programs. If \fIn\fR starts with "+", then it is interpreted as a number of weeks. If you immediately follow the \fBs\fR with the letter \fBa\fR, then \fBRemind\fR displays reminders on the calendar on the day they actually occur \fIas well as\fR on any preceding days specified by the reminder's \fIdelta\fR. .TP .B \-p\fR[\fBa\fR]\fIn\fR The \fB\-p\fR option is very similar to the \fB\-s\fR option, except that the output contains additional information for use by the \fBRem2PS\fR program, which creates a PostScript calendar. For this option, \fIn\fR cannot start with "+"; it must specify a number of months. The format of the \fB\-p\fR output is described in the \fBrem2ps(1)\fR man page. If you immediately follow the \fBp\fR with the letter \fBa\fR, then \fBRemind\fR displays reminders on the calendar on the day they actually occur \fIas well as\fR on any preceding days specified by the reminder's \fIdelta\fR. .TP .B \-l If you use the \-l option in conjunction with the \-p option, then \fBRemind\fR outputs additional information for back-end programs such as \fBrem2ps\fR. This additional information lets the back-end programs correlate a reminder with the source file and line number that produced it. .TP .B \-m The \fB\-m\fR option causes the \fB\-c\fR or \fB\-p\fR options to produce a calendar whose first column is Monday rather than Sunday. (This conforms to the international standard.) .TP .B \-v The \fB\-v\fR option makes the output of \fBRemind\fR slightly more verbose. Currently, this causes \fBRemind\fR to echo a bad line in case of an error, and to print a security message if a script tests the $RunOff system variable. .TP .B \-o The \fB\-o\fR option causes \fBRemind\fR to ignore all \fBONCE\fR directives. .TP .B \-t The \fB\-t\fR option causes \fBRemind\fR to trigger all non-expired reminders, regardless of the \fIdelta\fR supplied for each reminder. .TP .B \-t\fR\fIn\fR If you supply a number \fIn\fR after the \fB\-t\fR option, then \fBRemind\fR pretends that each non-expired reminder has a \fIdelta\fR of \fIn\fR days and triggers reminders accordingly. .TP .B \-h The \fB\-h\fR option ("hush...") suppresses certain warning and information messages. In particular, if no reminders are triggered, this mode produces no output. .TP .B \-a The \fB\-a\fR option causes \fBRemind\fR not to immediately trigger timed reminders that trigger on the current day. It also causes \fBRemind\fR not to place timed reminders in a calendar. If you supply two or more \fB\-a\fR options, then \fBRemind\fR \fIwill\fR trigger timed reminders that are in the future, but will not trigger timed reminders whose time has passed. (Regardless of how many \fB\-a\fR options you supply, \fBRemind\fR will not include timed reminders in the calendar if at least one \fB\-a\fR option is used.) .TP \fB\-q\fR The \fB\-q\fR option causes \fBRemind\fR not to queue timed reminders for later execution. .TP \fB\-f\fR The \fB\-f\fR option causes \fBRemind\fR to remain in the foreground when processing queued reminders, rather than forking off a background process to handle them. .TP .B \-e The \fB\-e\fR option diverts error messages (normally sent to the standard error stream) to the standard output stream. .TP .B \-d\fR\fIchars\fR The \fB-d\fR option enables certain debugging modes. The \fIchars\fR specify which modes to enable: .RS 2 .TP .B e Echo all input lines .TP .B x Trace all expression evaluation .TP .B t Display all trigger date computation .TP .B v Dump the variable table after execution of the reminder script .TP .B l Echo lines when displaying error messages .TP .B f Trace the reading of reminder files .RE .TP \fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]] Normally, reminders are issued in the order in which they are encountered in the reminder script. The \fB\-g\fR option cause \fBRemind\fR to sort reminders by date and time prior to issuing them. The optional \fBa\fR and \fBd\fR characters specify the sort order (ascending or descending) for the date, time and priority fields. See the section "Sorting Reminders" for more information. .TP \fB\-b\fR[\fIn\fR] Set the time format for the calendar and simple-calendar outputs. \fIN\fR can range from 0 to 2, with the default 0. A value of 0 causes times to be inserted in 12-hour (am/pm) format. 1 causes times to be inserted in 24-hour format, and 2 inhibits the automatic insertion of times in the calendar output. .TP \fB\-x\fR[\fIn\fR] Sets the iteration limit for the \fBSATISFY\fR clause of a \fBREM\fR command. Defaults to 150. .TP \fB\-k\fR\fIcmd\fR Instead of simply printing \fBMSG\fR-type reminders, this causes them to be passed to the specific \fIcmd\fR. You must use '%s' where you want the body to appear, and may need to enclose this option in quotes. Note that all shell characters in the body of the reminder are escaped with a backslash, and the entire body of the reminder is passed as a single argument. Note that this option \fBoverrides\fR the \fB\-r\fR option and the \fBRUN OFF\fR command. .PP .RS As an example, suppose you have an X Window program called \fBxmessage\fR that pops up a window and displays its invocation arguments. You could use: .PP .nf remind '\-kxmessage %s &' ... .fi .PP to have all of your \fBMSG\fR-type reminders processed using xmessage. .PP A word of warning: It is very easy to spawn dozens of xmessage processes with the above technique. So be very careful. Because all shell and whitespace characters are escaped, the program you execute with the \fB\-k\fR option must be prepared to handle the entire message as a single argument. .RE .TP \fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in the daemon mode. If \fIn\fR is supplied, it specifies how often (in minutes) \fBRemind\fR should wake up to check if the reminder script has been changed. \fIN\fR defaults to 1, and can range from 1 to 60. Note that the use of the \fB\-z\fR option also enables the \fB\-f\fR option. .PP .RS If you supply the option \fB\-z0\fR, \fBRemind\fR runs in a special mode called \fBserver mode\fR. This is documented in the tkremind man page; see tkremind(1). .RE .TP \fB\-u\fR\fIname\fR Runs \fBRemind\fR with the uid and gid of the user specified by \fIname\fR. The option changes the uid and gid as described, and sets the environment variables HOME, SHELL and USER to the home directory, shell, and user name, respectively, of the specified user. LOGNAME is also set to the specified user name. This option is meant for use in shell scripts that mail reminders to all users. Note that as of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR -- the RUN directive and shell() functions are disabled. .PP .RS Non-root users can also use the \fB\-u\fR option. However, in this case, it only changes the environment variables as described above. It does not change the effective uid or gid. .RE .TP \fB-y\fR Causes \fBRemind\fR to synthesize a tag for any reminder that lacks a TAG clause. .TP \fB\-i\fR\fIvar\fR\fB=\fR\fIexpr\fR Sets the value of the specified \fIvar\fR to \fIexpr\fR, and \fBpreserves\fR \fIvar\fR. \fIExpr\fR can be any valid \fBRemind\fR expression. See the section "Initializing Variables on the Command Line" for more details. .TP \fB\-i\fR\fIfunc\fR(\fIargs\fR)=\fIdefinition\fR Allows you to define a function on the command line. .PP If you supply a \fIdate\fR on the command line, it must consist of \fIday month year\fR, where \fIday\fR is the day of the month, \fImonth\fR is at least the first three letters of the English name of the month, and \fIyear\fR is a year (all 4 digits) from 1990 to about 2075. You can leave out the \fIday\fR, which then defaults to 1. .PP If you do supply a \fIdate\fR on the command line, then \fBRemind\fR uses it, rather than the actual system date, as its notion of "today." This lets you create calendars for future months, or test to see how your reminders will be triggered in the future. Similarly, you can supply a \fItime\fR (in 24-hour format -- for example, 17:15) to set \fBRemind\fR's notion of "now" to a particular time. Supplying a \fItime\fR on the command line also implicitly enables the \fB\-q\fR option and disables the \fB\-z\fR option. .PP If you would rather specify the date more succinctly, you can supply it as YYYY-MM-DD or YYYY/MM/DD. You can even supply a date and time on the command line as one argument: YYYY-MM-DD@HH:MM. .PP In addition, you can supply a \fIrepeat\fR parameter, which has the form *\fInum\fR. This causes \fBRemind\fR to be run \fInum\fR times, with the date incrementing on each iteration. You may have to enclose the parameter in quotes to avoid shell expansion. See the subsection "Repeated Execution" in the section "Calendar Mode" for more information. .SH REMINDER FILES .PP \fBRemind\fR uses scripts to control its operation. You can use any text editor capable of creating plain ASCII files to create a \fBRemind\fR script. The commands inside a script can range from the very simple and almost immediately understandable: .PP .nf REM 6 Jan MSG Dianne's birthday .fi .PP to the baroque and obscure: .PP .nf REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\ sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b! .fi .PP A reminder file consists of commands, with one command per line. Several lines can be continued using the backslash character, as in the above example. In this case, all of the concatenated lines are treated as a single line by \fBRemind\fR. Note that if an error occurs, \fBRemind\fR reports the line number of the last line of a continued line. .PP \fBRemind\fR ignores blank lines, and lines beginning with the '#' or ';' characters. You can use the semicolon as a comment character if you wish to pass a \fBRemind\fR script through the C pre-processor, which interprets the '#' character as the start of a pre-processing directive. .PP Note that \fBRemind\fR processes line continuations before anything else. For example: .PP .nf # This is a comment \\ This line is part of the comment because of line continuation \\ and so on. REM MSG This line is not ignored (no \\ above) .fi .PP \fBRemind\fR is not case sensitive; you can generally use any mixture of upper- or lower-case for commands, parameters, invocation options, etc. .SH THE REM COMMAND .PP The most powerful command in a \fBRemind\fR script is the \fBREM\fR command. This command is responsible for issuing reminders. Its syntax is: .PP .RS \fBREM\fR [\fBONCE\fR] [\fIdate_spec\fR] [\fIback\fR] [\fIdelta\fR] [\fIrepeat\fR] [\fBPRIORITY\fR \fIprio\fR] [\fBSKIP\fR | \fBBEFORE\fR | \fBAFTER\fR] [\fBOMIT\fR \fIomit_list\fR] [\fBOMITFUNC\fR \fIomit_function\fR] [\fBAT\fR \fItime\fR [\fItdelta\fR] [\fItrepeat\fR]] [\fBSCHED\fR \fIsched_function\fR] [\fBWARN\fR \fIwarn_function\fR] [\fBUNTIL\fR \fIexpiry_date\fR | \fBTHROUGH\fR \fIlast_date\fR] [\fBSCANFROM\fR \fIscan_date\fR | \fBFROM\fR \fIstart_date\fR] [\fBDURATION\fR \fIduration\fR] [\fBTAG\fR \fItag\fR] <\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR | \fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR> .I body .RE .PP The parts of the \fBREM\fR command can be specified in any order, except that the \fIbody\fR must come immediately after the \fBMSG\fR, \fBRUN\fR, \fBCAL\fR, \fBPS\fR, \fBPSFILE\fR or \fBSATISFY\fR keyword. .PP The \fBREM\fR token is optional, providing that the remainder of the command cannot be mistaken for another \fBRemind\fR command such as \fBOMIT\fR or \fBRUN\fR. The portion of the \fBREM\fR command before the \fBMSG\fR, \fBMSF\fR \fBRUN\fR, \fBCAL\fR or \fBSATISFY\fR clause is called a \fItrigger\fR. .PP .B "MSG, MSF, RUN, CAL, SPECIAL, PS and PSFILE" .PP These keywords denote the \fItype\fR of the reminder. (\fBSATISFY\fR is more complicated and will be explained later.) A \fBMSG\fR-type reminder normally prints a message to the standard output, after passing the \fIbody\fR through a special substitution filter, described in the section "The Substitution Filter." However, if you have used the \fB\-k\fR command-line option, then \fBMSG\fR-type reminders are passed to the appropriate program. Note that the options \fB\-c\fR, \fB\-s\fR, \fB\-p\fR and \fB\-n\fR disable the \fB\-k\fR option. .PP Note that you can omit the reminder type, in which case it defaults to \fBMSG\fR. So you can write: .PP .nf 6 January Dianne's Birthday .fi .PP although this is not recommended. .PP The \fBMSF\fR keyword is almost the same as the \fBMSG\fR keyword, except that the reminder is formatted to fit into a paragraph-like format. Three system variables control the formatting of \fBMSF\fR-type reminders - they are \fB$FirstIndent\fR, \fB$SubsIndent\fR and \fB$FormWidth\fR. They are discussed in the section "System Variables." The \fBMSF\fR keyword causes the spacing of your reminder to be altered - extra spaces are discarded, and two spaces are placed after periods and other characters, as specified by the system variables \fB$EndSent\fR and \fB$EndSentIg\fR. Note that if the body of the reminder includes newline characters (placed there with the %_ sequence), then the newlines are treated as the beginnings of new paragraphs, and the \fB$FirstIndent\fR indentation is used for the next line. You can use two consecutive newlines to have spaced paragraphs emitted from a single reminder body. .PP A \fBRUN\fR-type reminder also passes the \fIbody\fR through the substitution filter, but then executes the result as a system command. A \fBCAL\fR-type reminder is used only to place entries in the calendar produced when \fBRemind\fR is run with the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR options. .PP A \fBPS\fR or \fBPSFILE\fR-type reminder is used to pass PostScript code directly to the printer when producing PostScript calendars. This can be used to shade certain calendar entries (see the psshade() function), include graphics in the calendar, or almost any other purpose you can think of. You should not use these types of reminders unless you are an expert PostScript programmer. The \fBPS\fR and \fBPSFILE\fR reminders are ignored unless \fBRemind\fR is run with the \fB\-p\fR option. See the section "More about PostScript" for more details. .PP A \fBSPECIAL\fR-type reminder is used to pass "out-of-band" information from \fBRemind\fR to a calendar-producing back-end. It should be followed by a word indicating the type of special data being passed. The type of a special reminder depends on the back-end. For the \fBRem2PS\fR back-end, \fBSPECIAL PostScript\fR is equivalent to a \fBPS\fR-type reminder, and \fBSPECIAL PSFile\fR is equivalent to a \fBPSFILE\fR-type reminder. The body of a \fBSPECIAL\fR reminder is obviously dependent upon the back-end. .PP .B DATE SPECIFICATIONS .PP A \fIdate_spec\fR consists of zero to four parts. These parts are .I day (day of month), .I month (month name), .I year and .I weekday. .I Month and .I weekday are the English names of months and weekdays. At least the first three characters must be used. The following are examples of the various parts of a .I date_spec: .TP .I day: 1, 22, 31, 14, 3 .TP .I month: JANUARY, feb, March, ApR, may, Aug .TP .I year: 1990, 1993, 2030, 95 (interpreted as 1995). The year can range from 1990 to 2075. .TP .I weekday: Monday, tue, Wed, THU, Friday, saturday, sundAy .PP Note that there can be several .I weekday components separated by spaces in a .I date_spec. .PP .B INTERPRETATION OF DATE SPECIFICATIONS .PP The following examples show how date specifications are interpreted. .PP 1. Null date specification - the reminder is triggered every day. The trigger date for a specific run is simply the current system date. .PP 2. Only .I day present. The reminder is triggered on the specified day of each month. The trigger date for a particular run is the closest such day to the current system date. For example: .nf REM 1 MSG First of every month. REM 31 MSG 31st of every month that has 31 days. .fi .PP 3. Only .I month present. The reminder is triggered every day of the specified month. Example: .nf REM Feb MSG Every day in February .fi .PP 4. .I day and .I month present. Examples: .nf REM 6 Jan MSG Every 6th of January REM Feb 29 MSG Every 29th of February .fi .PP 5. Only .I year present. Example: .nf REM 1991 MSG Every day in 1991 .fi .PP 6. .I year and .I day present. Examples: .nf REM 1 1990 MSG 1st of every month in 1990 REM 1992 23 MSG 23rd of every month in 1992 .fi .PP 7. .I year and .I month present. Examples: .nf REM Feb 1991 MSG Every day in Feb 1991 REM 1992 September MSG Every day in Sept 1992 .fi .PP 8. .I year, month and .I day present. Examples: .nf REM 8 Jan 1991 MSG 8th January 1991. REM 1992 March 9 MSG 9th March 1992. .fi .PP 9. .I weekday only. Examples: .nf REM Sat MSG Every Saturday REM Mon Tue Wed Thu Fri MSG Every working day REM Monday Wednesday MSG Every Monday and Wednesday .fi .PP 10. .I weekday and .I day present. Examples: .nf REM Sat 1 MSG First Saturday of every month REM Mon Tue Wed Thu Fri 15 \\ MSG 1st working day after 15th of every month .fi .PP 11. .I weekday and .I month present. Examples: .nf REM Mon March MSG Every Monday in March REM Mon Tue Wed Thu Fri Feb MSG Every working day in February .fi .PP 12. .I weekday, month and .I day present. Examples: .nf REM Mon 1 March MSG First Monday in March REM Sat Sun 15 July MSG First Sat or Sun on or after 15 July .fi .PP 13. .I weekday and .I year present. Example: .nf REM Sat Sun 1991 MSG Every Saturday and Sunday in 1991 .fi .PP 14. .I weekday, day and .I year present. Examples: .nf REM Mon 15 1990 MSG 1st Mon after 15th of every month in 1990 REM Mon Tue Wed Thu Fri 1 1990 \\ MSG 1st working day of every month in 1990 .fi .PP 15. .I weekday, month and .I year present. Example: .nf REM Mon Wed 1991 Feb MSG Every Mon and Wed in Feb 1991. .fi .PP 16. .I weekday, day, month and .I year present. Example: .nf REM Mon Tue Wed Thu Fri 28 Oct 1990 \\ MSG 1st working day on or after 28 October 1990. .fi .PP Note that when both .I weekday and .I day are specified, .B Remind chooses the first date on or after the specified .I day that also satisfies the .I weekday constraint. It does this by picking the first date on or after the specified .I day that is listed in the list of .I weekdays. Thus, a reminder like: .PP .nf REM Mon Tue 28 Oct 1990 MSG Hi .fi .PP would be issued only on Monday, 29 October, 1990. It would not be issued on Tuesday, 30 October, 1990, since the 29th is the first date to satisfy the .I weekday constraints. .PP .B SHORT-HAND DATE SPECIFICATIONS .PP In addition to spelling out the day, month and year separately, you can specify YYYY-MM-DD or YYYY/MM/DD. For example, the following statements are equivalent: .PP .nf REM 5 June 2010 MSG Cool! REM 2010-06-05 MSG Cool! .fi .PP You can also specify a date and time as YYYY-MM-DD@HH:MM. These statements are equivalent: .PP .nf REM 19 Dec 2010 AT 16:45 MSG Hi REM 2010-12-19@16:45 MSG Hi .fi .PP There's one subtlety with short-hand date specifications: The following statements are \fInot\fR equivalent: .PP .nf REM 19 Dec 2010 AT 16:45 +60 MSG Hi REM 2010-12-19@16:45 +60 MSG Hi .fi .PP In the second statement, the "+60" is a \fIdelta\fR that applies to the date rather than a \fItdelta\fR that applies to the time. We recommend explicitly using the AT keyword with timed reminders. .PP .B THE REMIND ALGORITHM .PP \fBRemind\fR uses the following algorithm to compute a trigger date: Starting from the current date, it examines each day, one at a time, until it finds a date that satisfies the date specification, or proves to itself that no such date exists. (Actually, \fBRemind\fR merely \fIbehaves\fR as if it used this algorithm; it would be much too slow in practice. Internally, \fBRemind\fR uses much faster techniques to calculate a trigger date.) See DETAILS ABOUT TRIGGER COMPUTATION for more information. .PP .B BACKWARD SCANNING .PP Sometimes, it is necessary to specify a date as being a set amount of time before another date. For example, the last Monday in a given month is computed as the first Monday in the next month, minus 7 days. The \fIback\fR specification in the reminder is used in this case: .PP .nf REM Mon 1 \-7 MSG Last Monday of every month. .fi .PP A \fIback\fR is specified with one or two dashes followed by an integer. This causes \fBRemind\fR to move "backwards" from what would normally be the trigger date. The difference between \-\-7 and \-7 will be explained when the \fBOMIT\fR keyword is described. .PP .B ADVANCE WARNING .PP For some reminders, it is appropriate to receive advance warning of the event. For example, you may wish to be reminded of someone's birthday several days in advance. The \fIdelta\fR portion of the \fBREM\fR command achieves this. It is specified as one or two "+" signs followed by a number \fIn\fR. Again, the difference between the "+" and "++" forms will be explained under the \fBOMIT\fR keyword. \fBRemind\fR will trigger the reminder on computed trigger date, as well as on each of the \fIn\fR days before the event. Here are some examples: .PP .nf REM 6 Jan +5 MSG Remind me of birthday 5 days in advance. .fi .PP The above example would be triggered every 6th of January, as well as the 1st through 5th of January. .PP .B PERIODIC REMINDERS .PP We have already seen some built-in mechanisms for certain types of periodic reminders. For example, an event occurring every Wednesday could be specified as: .PP .nf REM Wed MSG Event! .fi .PP However, events that do not repeat daily, weekly, monthly or yearly require another approach. The \fIrepeat\fR component of the \fBREM\fR command fills this need. To use it, you must completely specify a date (year, month and day, and optionally weekday.) The \fIrepeat\fR component is an asterisk followed by a number specifying the repetition period in days. .PP For example, suppose you get paid every second Wednesday, and your last payday was Wednesday, 28 October, 1992. You can use: .PP .nf REM 28 Oct 1992 *14 MSG Payday .fi .PP This issues the reminder every 14 days, starting from the calculated trigger date. You can use \fIdelta\fR and \fIback\fR with \fIrepeat.\fR Note, however, that the \fIback\fR is used only to compute the initial trigger date; thereafter, the reminder repeats with the specified period. Similarly, if you specify a weekday, it is used only to calculate the initial date, and does not affect the repetition period. .PP .B SCANFROM \fRand\fB FROM .PP The \fBSCANFROM\fR and \fBFROM\fR keywords are for advanced \fBRemind\fR programmers only, and will be explained in the section "Details about Trigger Computation" near the end of this manual. Note that \fBSCANFROM\fR is available only in versions of \fBRemind\fR from 03.00.04 up. \fBFROM\fR is available only from 03.01.00 and later. .PP .B PRIORITY .PP The \fBPRIORITY\fR keyword must be followed by a number from 0 to 9999. It is used in calendar mode and when sorting reminders. If two reminders have the same trigger date and time, then they are sorted by priority. If the \fBPRIORITY\fR keyword is not supplied, a default priority of 5000 is used. (This default can be changed by adjusting the system variable \fB$DefaultPrio\fR. See the section "System Variables" for more information.) .PP .B EXPIRY DATES .PP Some reminders should be issued periodically for a certain time, but then expire. For example, suppose you have a class every Friday, and that your last class is on 11 December 1992. You can use: .PP .nf REM Fri UNTIL 11 Dec 1992 MSG Class today. .fi .PP Another example: Suppose you have jury duty from 30 November 1992 until 4 December 1992. The following reminder will issue the message every day of your jury duty, as well as 2 days ahead of time: .PP .nf REM 1992-11-30 *1 +2 UNTIL 1992-12-04 MSG Jury duty .fi .PP Note that the \fIrepeat\fR of *1 is necessary; without it, the reminder would be issued only on 30 November (and the two days preceding.) .PP As a special case, you can use the \fBTHROUGH\fR keyword instead of *1 and \fBUNTIL\fR. The following two \fBREM\fR commands are equivalent: .PP .nf REM 1992-11-30 *1 +2 UNTIL 1992-12-04 MSG Jury duty REM 1992-11-30 +2 THROUGH 1992-12-04 MSG Jury duty .fi .PP .B THE ONCE KEYWORD .PP Sometimes, it is necessary to ensure that reminders are run only once on a given day. For example, if you have a reminder that makes a backup of your files every Friday: .PP .nf REM Fri RUN do_backup .fi .PP (Here, \fIdo_backup\fR is assumed to be a program or shell script that does the work.) If you run \fBRemind\fR from your .login script, for example, and log in several times per day, the \fIdo_backup\fR program will be run each time you log in. If, however, you use the \fBONCE\fR keyword in the reminder, the \fBRemind\fR checks the last access date of the reminder script. If it is the same as the current date, \fBRemind\fR assumes that it has already been run, and will not issue reminders containing the \fBONCE\fR keyword. .PP Note that if you view or edit your reminder script, the last access date will be updated, and the \fBONCE\fR keyword will not operate properly. If you start \fBRemind\fR with the \fB\-o\fR option, then the \fBONCE\fR keyword will be ignored. .PP .B LOCALLY OMITTING WEEKDAYS .PP The \fBOMIT\fR portion of the \fBREM\fR command is used to "omit" certain days when counting the \fIdelta\fR or \fIback\fR. It is specified using the keyword \fBOMIT\fR followed by a list of weekdays. Its action is best illustrated with examples: .PP .nf REM 1 +1 OMIT Sat Sun MSG Important Event .fi .PP This reminder is normally triggered on the first of every month, as well as the day preceding it. However, if the first of the month falls on a Sunday or Monday, then the reminder is triggered starting from the previous Friday. This is because the \fIdelta\fR of +1 does not count Saturday or Sunday when it counts backwards from the trigger date to determine how much advance warning to give. .PP Contrast this with the use of "++1" in the above command. In this case, the reminder is triggered on the first of each month, as well as the day preceding it. The omitted days are counted. .PP .nf REM 1 \-1 OMIT Sat Sun MSG Last working day of month .fi .PP Again, in the above example, the \fIback\fR of \-1 normally causes the trigger date to be the last day of the month. However, because of the \fBOMIT\fR clause, if the first of the month falls on a Sunday or Monday, the trigger date is moved backwards past the weekend to Friday. (If you have globally omitted holidays, the reminder will be moved back past them, also. See "The OMIT command" for more details.) .PP By comparison, if we had used "\-\-1", the reminder would be triggered on the last day of the month, regardless of the \fBOMIT\fR. .PP .B COMPUTED LOCAL OMITS .PP The \fBOMITFUNC\fR phrase of the \fBREM\fR command allows you to supply a function that determines whether or not a date is omitted. The function is passed a single parameter of type \fBDATE\fR, and must return a non-zero integer if the date is considered "omitted" and 0 otherwise. Here's an example: .PP .nf FSET _third(x) (day(x) % 3) || \\ (wkdaynum(x) == 0) || \\ (wkdaynum(x) == 6) REM OMITFUNC _third AFTER MSG Working day divisible by 3 .fi .PP In the example above, the reminder is triggered every Monday to Friday whose day-of-month number is divisible by three. Here's how it works: .TP .B o The \fBOMITFUNC _third\fR portion causes all days for which \fB_third(x)\fR returns non-zero to be considered "omitted". This causes all days whose day-of-month number is \fInot\fR a multiple of three to be omitted. Note that _third also returns non-zero if the weekday is Sunday or Saturday. .TP .B o The \fBAFTER\fR keyword causes the reminder to be moved after a block of omitted days. .PP The combination of OMITFUNC and AFTER keyword causes the reminder to be issued on all days whose day-of-month number is divisible by three, but not on Saturday or Sunday. .PP Note that if you use \fBOMITFUNC\fR, then a local \fBOMIT\fR is \fIignored\fR as are \fIall global OMITs\fR. If you want to omit specific weekdays, your omit function will need to test for them specifically. If you want to take into account the global \fBOMIT\fR context, then your omit function will need to test for that explicitly (using the \fBisomitted()\fR function.) .PP Note that an incorrect \fBOMITFUNC\fR might cause all days to be considered omitted. For that reason, when \fBRemind\fR searches through omitted days, it terminates the search after the \fBSATISFY\fR iteration limit (command-line option \fB\-x\fR.) .PP .B TIMED REMINDERS .PP Timed reminders are those that have an \fBAT\fR keyword followed by a \fItime\fR and optional \fItdelta\fR and \fItrepeat\fR. The \fItime\fR must be specified in 24-hour format, with 0:00 representing midnight, 12:00 representing noon, and 23:59 representing one minute to midnight. You can use either a colon or a period to separate the hours from the minutes. That is, 13:39 and 13.39 are equivalent. .PP \fBRemind\fR treats timed reminders specially. If the trigger date for a timed reminder is the same as the current system date, the reminder is queued for later activation. When \fBRemind\fR has finished processing the reminder file, it puts itself in the background, and activates timed reminders when the system time reached the specified time. .PP If the trigger date is \fInot\fR the same as the system date, the reminder is not queued. .PP For example, the following reminder, triggered every working day, will emit a message telling you to leave at 5:00pm: .PP .nf REM Mon Tue Wed Thu Fri AT 17:00 MSG Time to leave! .fi .PP The following reminder will be triggered on Thursdays and Fridays, but will only be queued on Fridays: .PP .nf REM Fri ++1 AT 13:00 MSG Lunch at 1pm Friday. .fi .PP The \fItdelta\fR and \fItrepeat\fR have the same form as a \fIrepeat\fR and \fIdelta\fR, but are specified in minutes. For example, this reminder will be triggered at 12:00pm as well as 45 minutes before: .PP .nf REM AT 12:00 +45 MSG Example .fi .PP The following will be issued starting at 10:45, every half hour until 11:45, and again at noon. .PP .nf REM AT 12:00 +75 *30 MSG Example2 .fi .PP The "+75" means that the reminder is issued starting 75 minutes before noon; in other words, at 10:45. The *30 specifies that the reminder is subsequently to be issued every 30 minutes. Note that the reminder is always issued at the specified time, even if the \fItdelta\fR is not a multiple of the \fItrepeat\fR. So the above example is issued at 10:45am, 11:15am, 11:45am, and 12:00pm. Note that in the time specification, there is no distinction between the "+" and "++" forms of \fItdelta\fR. .PP Normally, \fBRemind\fR will issue timed reminders as it processes the reminder script, as well as queuing them for later. If you do not want \fBRemind\fR to issue the reminders when processing the script, but only to queue them for later, use the \fB\-a\fR command-line option. If you do not want reminders to be queued for later, use the \fB\-q\fR command-line option. .PP Normally, \fBRemind\fR forks a background process to handle queued reminders. If you want \fBRemind\fR to remain in the foreground, use the \fB\-f\fR command-line option. This is useful, for example, in .xinitrc scripts, where you can use the command: .PP .nf remind \-fa myreminders & .fi .PP This ensures that when you exit X-Windows, the \fBRemind\fR process is killed. .PP .B WARNING ABOUT TIMED REMINDERS .PP Note: If you use user-defined functions or variables (described later) in the bodies of timed reminders, then when the timed reminders are activated, the variables and functions have the definitions that were in effect at the end of the reminder script. These definitions may \fInot\fR necessarily be those that were in effect at the time the reminder was queued. .PP .B THE SCHED AND WARN KEYWORDS .PP The \fBSCHED\fR keyword allows more precise control over the triggering of timed reminders, and the \fBWARN\fR keyword allows precise control over the advance triggering of all types of reminders. However, discussion must be deferred until after expressions and user-defined functions are explained. See the subsection "Precise Scheduling" further on. .PP .B TAG AND DURATION .PP The \fBTAG\fR keyword lets you "tag" certain reminders. This facility is used by certain back-ends or systems built around \fBRemind\fR, such as \fBTkRemind\fR. These back-ends have specific rules about tags; see their documentation for details. .PP The \fBTAG\fR keyword is followed by a tag consisting of up to 48 characters. You can have as many TAG clauses as you like in a given REM statement. .PP If you supply the \fB\-y\fR option to \fBRemind\fR, then any reminder that lacks a \fBTAG\fR will have one synthesized. The synthesized tag consists of the characters "__syn__" followed by the hexadecimal representation of the MD5 sum of the REM command line. This lets you give a more-or-less unique identifier to each distinct REM command. .PP The \fBDURATION\fR keyword makes sense only for timed reminders; it specifies the duration of an event. Currently, this is not used, but it may be used in future by back-ends or scheduling systems built around \fBRemind\fR. For example, if you have a 90-minute meeting starting at 1:00pm, you could use: .PP .nf REM 5 March 1999 AT 13:00 DURATION 1:30 MSG Meeting .fi .PP Note that \fIduration\fR is specified in hours and minutes. .PP .SH THE SUBSTITUTION FILTER .PP Before being processed, the body of a .B REM command is passed through a substitution filter. The filter scans for sequences "%x" (where "x" is any letter and certain other characters) and performs substitutions as shown below. (All dates refer to the trigger date of the reminder.) .TP .B %a is replaced with "on \fIweekday, day month, year\fR" .RS For example, consider the reminder: .PP REM 18 Oct 1990 +4 MSG Meeting with Bob %a. .PP On 16 October 1990, it would print "Meeting with Bob on Thursday, 18 October, 1990." .PP On 17 October 1990, it would print "Meeting with Bob tomorrow." .PP On 18 October 1990, it would print "Meeting with Bob today." .RE .TP .B %b is replaced with "in \fIdiff\fR day's time" where .I diff is the .B actual number of days between the current date and the trigger date. (\fBOMITs\fR have no effect.) .RS For example, consider: .PP REM 18 Oct 1990 +4 MSG Meeting with Bob %b. .PP On 16 October 1990, it would print "Meeting with Bob in 2 days' time." .PP On 17 October 1990, it would print "Meeting with Bob tomorrow." .PP On 18 October 1990, it would print "Meeting with Bob today." .RE .TP .B %c is replaced with "on \fIweekday\fR" .RS Example: REM 18 Oct 1990 +4 MSG Meeting with Bob %c. .PP On 16 October 1990, it would print "Meeting with Bob on Thursday." .PP On 17 October 1990, it would print "Meeting with Bob tomorrow." .PP On 18 October 1990, it would print "Meeting with Bob today." .RE .TP .B %d is replaced with "\fIday\fR", the day of the month. .TP .B %e is replaced with "on \fIdd-mm-yyyy\fR" .TP .B %f is replaced with "on \fImm-dd-yyyy\fR" .TP .B %g is replaced with "on \fIweekday, day month\fR" .TP .B %h is replaced with "on \fIdd-mm\fR" .TP .B %i is replaced with "on \fImm-dd\fR" .TP .B %j is replaced with "on \fIweekday, month day-th, year\fR" This form appends the characters "st", "nd", "rd" or "th" to the day of the month, as appropriate. .TP .B %k is replaced with "on \fIweekday, month day-th\fR" .TP .B %l is replaced with "on \fIyyyy-mm-dd\fR" .TP .B %m is replaced with "\fImonth\fR", the name of the month. .TP .B %n is replaced with the number (1 to 12) of the month. .TP .B %o is replaced with " (today)" if and only if the current system date is the same as the date being used by .B Remind as the current date. Recall that you can specify a date for .B Remind to use on the command line. This substitution is not generally useful in a .B REM command, but is useful in a .B BANNER command. (See "The BANNER Command.") .TP .B %p is replaced with "s" if the .I diff between the current date and the trigger date is not 1. You can use this to construct reminders like: .RS REM 1 Jan +4 MSG %x day%p to go before New Year! .RE .TP .B %q is replaced with "'s" if the .I diff between the trigger date and the current date is 1. Otherwise, it is replaced with "s'" This can be used as follows: .RS REM 1 Jan +4 MSG New Year in %x day%q time! .RE .TP .B %r is replaced with the day of the month (01 to 31) padded with a leading zero if needed to pad to two digits. .TP .B %s is replaced with "st", "nd", "rd" or "th" depending on the day of the month. .TP .B %t is replaced with the number of the month (01 to 12) padded to two digits with a leading zero. .TP .B %u is replaced with "on \fIweekday, day-th month, year\fR" This is similar to .B %a except that "st", "nd", "rd" or "th" is added to the .I day as appropriate. .TP .B %v is replaced with "on \fIweekday, day-th month\fR" .TP .B %w is replaced with "\fIweekday\fR", the name of the day of the week. .TP .B %x is replaced with the .I diff between the current date and the trigger date. The .I diff is defined as the actual number of days between these two dates; .B OMITs are not counted. (Strict date subtraction is performed.) .TP .B %y is replaced with "\fIyear\fR", the year of the trigger date. .TP .B %z is replaced with "\fIyy\fR", the last two digits of the year. .TP .B %_ (percent-underscore) is replaced with a newline. You can use this to achieve multi-line reminders. .TP .B %1 is replaced with "now", "\fIm\fR minutes from now", "\fIm\fR minutes ago", "\fIh\fR hours from now", "\fIh\fR hours ago", "\fIh\fR hours and \fIm\fR minutes from now" or "\fIh\fR hours and \fIm\fR minutes ago", as appropriate for a timed reminder. Note that unless you specify the \fB\-a\fR option, timed reminders will be triggered like normal reminders, and thus a timed reminder that occurred earlier in the day may be triggered. This causes the need for the "...ago" forms. .TP .B %2 is replaced with "at \fIhh\fR:\fImm\fRam" or "..pm" depending on the .B AT time of the reminder. .TP .B %3 is replaced with "at \fIhh\fR:\fImm\fR" in 24-hour format. .TP .B %4 is replaced with "\fImm\fR" where \fImm\fR is the number of minutes between "now" and the time specified by \fBAT\fR. If the \fBAT\fR time is earlier than the current time, then the result is negative. .TP .B %5 is replaced with "\fIma\fR" where \fIma\fR is the absolute value of the number produced by \fB%4\fR. .TP .B %6 is replaced with "ago" or "from now", depending on the relationship between the \fBAT\fR time and the current time. .TP .B %7 is replaced with the number of hours between the \fBAT\fR time and the current time. It is always non-negative. .TP .B %8 is replaced with the number of minutes between the \fBAT\fR time and the current time, after the hours (\fB%7\fR) have been subtracted out. This is a number ranging from 0 to 59. .TP .B %9 is replaced with "s" if the value produced by \fB%8\fR is not 1. .TP .B %0 is replaced with "s" if the value produced by \fB%7\fR is not 1. .TP .B %! is replaced with "is" if the current time is before the \fBAT\fR time, or "was" if it is after. .TP .B %@ is similar to \fB%2\fR but displays the current time. .TP .B %# is similar to \fB%3\fR but displays the current time. .TP .B %" (percent-doublequote - ") is removed. This sequence is not used by the substitution filter, but is used to tell \fBRemind\fR which text to include in a calendar entry when the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR option is chosen. See "Calendar Mode" .PP Notes: .TP o .B Remind normally prints a blank line after each reminder; if the last character of the body is "%", the blank line will not be printed. .TP o Substitutions a, b, c, e, f, g, h, i, j, k, l, u and v all are replaced with "today" if the current date equals the trigger date, or "tomorrow" if the trigger date is one day after the current date. Thus, they are .B not the same as substitutions built up from the simpler %w, %y, etc. sequences. .TP o Any of the substitutions dealing with time (0 through 9 and '!') produce undefined results if used in a reminder that does not have an \fBAT\fR keyword. Also, if a reminder has a \fIdelta\fR and may be triggered on several days, the time substitutions ignore the date. Thus, the \fB%1\fR substitution may report that a meeting is in 15 minutes, for example, even though it may only be in 2 days time, because a \fIdelta\fR has triggered the reminder. It is recommended that you use the time substitutions only in timed reminders with no \fIdelta\fR that are designed to be queued for timed activation. .TP o Capital letters can be used in the substitution sequence, in which case the first character of the substituted string is capitalized (if it is normally a lower-case letter.) .TP o All other characters following a "%" sign are simply copied. In particular, to get a "%" sign out, use "%%" in the body. To start the body of a reminder with a space, use "% ", since .B Remind normally scans for the first non-space character after a .B MSG, .B CAL or .B RUN token. .SH THE OMIT COMMAND .PP In addition to being a keyword in the \fBREM\fR command, \fBOMIT\fR is a command in its own right. Its syntax is: .PP .RS \fBOMIT\fR \fIday\fR \fImonth\fR [\fIyear\fR] .PP or: .PP \fBOMIT\fR \fIday1\fR \fImonth1\fR \fIyear1\fR \fBTHROUGH\fR \fIday2\fR \fImonth2\fR \fIyear2\fR .RE .PP The \fBOMIT\fR command is used to "globally" omit certain days (usually holidays). These globally-omitted days are skipped by the "\-" and "+" forms of \fIback\fR and \fIdelta\fR. Some examples: .PP .nf OMIT 1 Jan OMIT 7 Sep 1992 .fi .PP The first example specifies a holiday that occurs on the same date each year - New Year's Day. The second example specifies a holiday that changes each year - Labour Day. For these types of holidays, you must create an \fBOMIT\fR command for each year. (Later, in the description of expressions and some of the more advanced features of \fBRemind\fR, you will see how to automate this for some cases.) .PP As with the REM command, you can use shorthand specifiers for dates; the following are equivalent: .PP .nf OMIT 7 Sep 1992 OMIT 1992-09-07 .fi .PP For convenience, you can use a \fIdelta\fR and \fBMSG\fR or \fBRUN\fR keyword in the \fBOMIT\fR command. The following sequences are equivalent: .PP .nf OMIT 1 Jan REM 1 Jan +4 MSG New year's day is %b! and OMIT 1 Jan +4 MSG New year's day is %b! .fi .PP The \fBTHROUGH\fR keyword lets you conveniently OMIT a range of days. The starting and ending points must be fully-specified (ie, they must include day, month and year.). For example, the following sequences are equivalent: .PP .nf OMIT 3 Jan 2011 OMIT 4 Jan 2011 OMIT 5 Jan 2011 and OMIT 3 Jan 2011 THROUGH 5 Jan 2011 .fi .PP You can make a THROUGH \fBOMIT\fR do double-duty as a \fBREM\fR command: .PP .nf OMIT 6 Sep 2010 THROUGH 10 Sep 2010 MSG Vacation .fi .PP You can debug your global OMITs with the following command: .PP .nf OMIT DUMP .fi .PP The OMIT DUMP command prints the current global omits to standard output. .PP .B THE BEFORE, AFTER AND SKIP KEYWORDS .PP Normally, days that are omitted, whether by a global \fBOMIT\fR command or the local \fBOMIT\fR or \fBOMITFUNC\fR keywords in a \fBREM\fR statement, only affect the counting of the \-\fIback\fR or the +\fIdelta\fR. For example, suppose you have a meeting every Wednesday. Suppose, too, that you have indicated 11 Nov as a holiday: .PP .nf OMIT 11 Nov +4 MSG Remembrance Day REM Wed +1 MSG Code meeting %b. .fi .PP The above sequence will issue a reminder about a meeting for 11 November 1992, which is a Wednesday. This is probably incorrect. There are three options: .TP .B BEFORE This keyword moves the reminder to before any omitted days. Thus, in the above example, use of \fBBEFORE\fR would cause the meeting reminder to be triggered on Tuesday, 10 November 1992. .TP .B AFTER This keyword moves the reminder to after any omitted days. In the above example, the meeting reminder would be triggered on Thursday, 12 November 1992. .TP .B SKIP This keyword causes the reminder to be skipped completely on any omitted days. Thus, in the above example, the reminder would not be triggered on 11 November 1992. However, it would be triggered as usual on the following Wednesday, 18 November 1992. .PP The \fBBEFORE\fR and \fBAFTER\fR keywords move the trigger date of a reminder to before or after a block of omitted days, respectively. Suppose you normally run a backup on the first day of the month. However, if the first day of the month is a weekend or holiday, you run the backup on the first working day following the weekend or holiday. You could use: .PP .nf REM 1 OMIT Sat Sun AFTER RUN do_backup .fi .PP Let's examine how the trigger date is computed. The \fB1\fR specifies the first day of the month. The local \fBOMIT\fR keyword causes the \fBAFTER\fR keyword to move the reminder forward past weekends. Finally, the \fBAFTER\fR keyword will keep moving the reminder forward until it has passed any holidays specified with global \fBOMIT\fR commands. .SH THE INCLUDE COMMAND .PP \fBRemind\fR allows you to include other files in your reminder script, similar to the C preprocessor #include directive. For example, your system administrator may maintain a file of holidays or system-wide reminders. You can include these in your reminder script as follows: .PP .nf INCLUDE /usr/share/remind/holidays INCLUDE /usr/share/remind/reminders .fi .PP (The actual pathnames vary from system to system - ask your system administrator.) .PP \fBINCLUDE\fR files can be nested up to a depth of 8. .PP If you specify a filename of "-" in the \fBINCLUDE\fR command, \fBRemind\fR will begin reading from standard input. .PP If you specify a \fIdirectory\fR as the argument to \fBINCLUDE\fR, then \fBRemind\fR will process all files in that directory that match the shell patterm "*.rem". The files are processed in sorted order; the sort order matches that used by the shell when it expands "*.rem". .SH THE RUN COMMAND .PP If you include other files in your reminder script, you may not always entirely trust the contents of the other files. For example, they may contain \fBRUN\fR-type reminders that could be used to access your files or perform undesired actions. The \fBRUN\fR command can restrict this: If you include the command \fBRUN OFF\fR in your top-level reminder script, any reminder or expression that would normally execute a system command is disabled. \fBRUN ON\fR will re-enable the execution of system commands. Note that the \fBRUN ON\fR command can \fIonly\fR be used in your top-level reminder script; it will \fInot\fR work in any files accessed by the \fBINCLUDE\fR command. This is to protect you from someone placing a \fBRUN ON\fR command in an included file. However, the \fBRUN OFF\fR command can be used at top level or in an included file. .PP If you run \fBRemind\fR with the \fB\-r\fR command-line option, \fBRUN\fR-type reminders and the \fBshell()\fR function will be disabled, regardless of any \fBRUN\fR commands in the reminder script. However, any command supplied with the \fB\-k\fR option will still be executed. .PP One use of the \fBRUN\fR command is to provide a secure interface between \fBRemind\fR and the \fBElm\fR mail system. The \fBElm\fR system can automatically scan incoming mail for reminder or calendar entries, and place them in your calendar file. To use this feature, you should set the calendar filename option under \fBElm\fR to be something like "~/.reminders.in", \fInot\fR your main reminder file! This is so that any \fBRUN ON\fR commands mailed to you can never be activated. .PP Then, you can use the \fBElm\fR \fIscan message for calendar entries\fR command to place reminders prefaced by "->" into .reminders.in. In your main .reminders file, include the following lines: .PP .nf RUN OFF # Disable RUN INCLUDE .reminders.in RUN ON # Re-enable RUN .fi .PP In addition, \fBRemind\fR contains a few other security features. It will not read a file that is group- or world-writable. It will not run set-uid. If it reads a file you don't own, it will disable RUN and the shell() function. And if it is run as \fIroot\fR, it will only read files owned by \fIroot\fR. .PP .SH THE BANNER COMMAND .PP When \fBRemind\fR first issues a reminder, it prints a message like this: .PP .nf Reminders for Friday, 30th October, 1992 (today): .fi .PP (The banner is not printed if any of the calendar-producing options is used, or if the \fB\-k\fR option is used.) .PP The \fBBANNER\fR command lets you change the format. It should appear before any \fBREM\fR commands. The format is: .PP .RS \fBBANNER\fR \fIformat\fR .RE .PP The \fIformat\fR is similar to the \fIbody\fR of a \fBREM\fR command. It is passed through the substitution filter, with an implicit trigger of the current system date. Thus, the default banner is equivalent to: .PP .nf BANNER Reminders for %w, %d%s %m, %y%o: .fi .PP You can disable the banner completely with BANNER %. Or you can create a custom banner: .PP .nf BANNER Hi - here are your reminders for %y-%t-%r: .fi .SH CONTROLLING THE OMIT CONTEXT .PP Sometimes, it is necessary to temporarily change the global \fBOMITs\fR that are in force for a few reminders. Three commands allow you to do this: .TP .B PUSH-OMIT-CONTEXT This command saves the current global \fBOMITs\fR on an internal stack. .TP .B CLEAR-OMIT-CONTEXT This command clears all of the global \fBOMITs\fR, starting you off with a "clean slate." .TP .B POP-OMIT-CONTEXT This command restores the global \fBOMITs\fR that were saved by the most recent \fBPUSH-OMIT-CONTEXT\fR. .PP For example, suppose you have a block of reminders that require a clear \fBOMIT\fR context, and that they also introduce unwanted global \fBOMITs\fR that could interfere with later reminders. You could use the following fragment: .PP .nf PUSH-OMIT-CONTEXT # Save the current context CLEAR-OMIT-CONTEXT # Clean the slate # Block of reminders goes here POP-OMIT-CONTEXT # Restore the saved omit context .fi .SH EXPRESSIONS .PP In certain contexts, to be described later, \fBRemind\fR will accept expressions for evaluation. \fBRemind\fR expressions resemble C expressions, but operate on different types of objects. .PP .B DATA TYPES .PP \fBRemind\fR expressions operate on five types of objects: .TP .B INT The \fBINT\fR data type consists of the integers representable in one machine word. The \fBINT\fR data type corresponds to the C "int" type. .TP .B STRING The \fBSTRING\fR data type consists of strings of characters. It is somewhat comparable to a C character array, but more closely resembles the string type in BASIC. .TP .B TIME The \fBTIME\fR data type consists of times of the day. The \fBTIME\fR data type is internally stored as an integer representing the number of minutes since midnight. .TP .B DATE The \fBDATE\fR data type consists of dates (later than 1 January 1990.) Internally, \fBDATE\fR objects are stored as the number of days since 1 January 1990. .TP .B DATETIME The \fBDATETIME\fR data type consists of a date and time together. Internally, \fBDATETIME\fR objects are stored as the number of minutes since midnight, 1 January 1990. You can think of a \fBDATETIME\fR object as being the combination of \fBDATE\fR and \fBTIME\fR parts. .PP .B CONSTANTS .PP The following examples illustrate constants in \fBRemind\fR expressions: .TP .B INT constants 12, 36, \-10, 0, 1209 .TP .B STRING constants "Hello there", "This is a test", "\\n\\gosd\\w", "" .PP .RS Note that the empty string is represented by "", and that backslashes in a string are \fInot\fR interpreted specially, as in they are in C. .RE .TP .B TIME constants 12:33, 0:01, 14:15, 16:42, 12.16, 13.00, 1.11 .PP .RS Note that \fBTIME\fR constants are written in 24-hour format. Either the period or colon can be used to separate the minutes from the hours. However, Remind will consistently output times using only one separator character. (The output separator character is chosen at compile-time.) .RE .TP .B DATE constants \fBDATE\fR constants are expressed as 'yyyy/mm/dd' or 'yyyy-mm-dd', and the single quotes \fImust\fR be supplied. This distinguishes date constants from division or subtraction of integers. Examples: .PP .RS \'1993/02/22', '1992-12-25', '1999/01/01' .PP Note that \fBDATE\fR values are \fIprinted\fR without the quotes. Although either '-' or '/' is accepted as a date separator on input, when dates are printed, only one will be used. The choice of whether to use '-' or '/' is made at compile-time. Note also that versions of \fBRemind\fR prior to 03.00.01 did not support date constants. In those versions, you must create dates using the \fBdate()\fR function. Also, versions prior to 03.00.02 did not support the '-' date separator. .RE .TP .B DATETIME constants \fBDATETIME\fR constants are expressed similarly to \fBDATE\fR constants with the addition of an "@HH:MM" part. For example: .PP .RS \'2008-04-05@23:11', '1999/02/03@14:06', '2001-04-07@08:30' .PP \fBDATETIME\fR values are printed without the quotes. Notes about date and time separator characters for \fBDATE\fR and \fBTIME\fR constants apply also to \fBDATETIME\fR constants. .RE .PP .B OPERATORS .PP \fBRemind\fR has the following operators. Operators on the same line have equal precedence, while operators on lower lines have lower precedence than those on higher lines. The operators approximately correspond to C operators. .PP .nf ! - (unary logical negation and arithmetic negation) * / % + - < <= > >= == != && || .fi .PP .B DESCRIPTION OF OPERATORS .PP .TP .B ! Logical negation. Can be applied to an \fBINT\fR type. If the operand is non-zero, returns zero. Otherwise, returns 1. .TP .B \- Unary minus. Can be applied to an \fBINT\fR. Returns the negative of the operand. .TP .B * Multiplication. Returns the product of two \fBINT\fRs. .TP .B / Integer division. Returns the quotient of two \fBINT\fRs, discarding the remainder. .TP .B % Modulus. Returns the remainder upon dividing one \fBINT\fR by another. .TP .B + Has several uses. These are: .PP .RS \fBINT\fR + \fBINT\fR - returns the sum of two \fBINT\fRs. .PP \fBINT\fR + \fBTIME\fR or \fBTIME\fR + \fBINT\fR - returns a \fBTIME\fR obtained by adding \fBINT\fR minutes to the original \fBTIME\fR. .PP \fBINT\fR + \fBDATE\fR or \fBDATE\fR + \fBINT\fR - returns a \fBDATE\fR obtained by adding \fBINT\fR days to the original \fBDATE\fR. .PP \fBINT\fR + \fBDATETIME\fR or \fBDATETIME\fR + \fBINT\fR - returns a \fBDATETIME\fR obtained by adding \fBINT\fR minutes to the original \fBDATETIME\fR. .PP \fBSTRING\fR + \fBSTRING\fR - returns a \fBSTRING\fR that is the concatenation of the two original \fBSTRING\fRs. .PP \fBSTRING\fR + anything or anything + \fBSTRING\fR - converts the non-\fBSTRING\fR argument to a \fBSTRING\fR, and then performs concatenation. See the \fBcoerce()\fR function. .RE .TP .B \- Has several uses. These are: .PP .RS \fBINT\fR - \fBINT\fR - returns the difference of two \fBINT\fRs. .PP \fBDATE\fR - \fBDATE\fR - returns (as an \fBINT\fR) the difference in days between two \fBDATE\fRs. .PP \fBTIME\fR - \fBTIME\fR - returns (as an \fBINT\fR) the difference in minutes between two \fBTIME\fRs. .PP \fBDATETIME\fR - \fBDATETIME\fR - returns (as an \fBINT\fR) the difference in minutes between two \fBDATETIME\fRs. .PP \fBDATE\fR - \fBINT\fR - returns a \fBDATE\fR that is \fBINT\fR days earlier than the original \fBDATE\fR. .PP \fBTIME\fR - \fBINT\fR - returns a \fBTIME\fR that is \fBINT\fR minutes earlier than the original \fBTIME\fR. .PP \fBDATETIME\fR - \fBINT\fR - returns a \fBDATETIME\fR that is \fBINT\fR minutes earlier than the original \fBDATETIME\fR. .RE .TP .B <, <=, >, and >= These are the comparison operators. They can take operands of any type, but both operands must be of the same type. The comparison operators return 1 if the comparison is true, or 0 if it is false. Note that string comparison is done following the lexical ordering of characters on your system, and that upper and lower case \fIare\fR distinct for these operators. .TP .B ==, != == tests for equality, returning 1 if its operands are equal, and 0 if they are not. != tests for inequality. .PP .RS If the operands are not of the same type, == returns 0 and != returns 1. Again, string comparisons are case-sensitive. .RE .TP .B && This is the logical AND operator. Both of its operands must be of type \fBINT\fR. It returns 1 if both operands are non-zero, and 0 otherwise. .TP .B || This is the logical OR operator. Both of its operands must be of type \fBINT\fR. It returns 1 if either operand is non-zero, and 0 otherwise. .PP .B NOTES .PP Operators of equal precedence are \fIalways\fR evaluated from left to right, except where parentheses dictate otherwise. This is important, because the enhanced "+" operator is not necessarily associative. For example: .PP .nf 1 + 2 + "string" + 3 + 4 yields "3string34" 1 + (2 + "string") + (3 + 4) yields "12string7" 12:59 + 1 + "test" yields "13:00test" 12:59 + (1 + "test") yields "12:591test" .fi .PP The logical operators are \fInot\fR so-called short-circuit operators, as they are in C. Both operands are always evaluated. Thus, an expression such as: .PP .nf (f!=0) && (100/f <= 3) .fi .PP will cause an error if f is zero. .PP .B VARIABLES .PP \fBRemind\fR allows you to assign values to variables. The \fBSET\fR command is used as follows: .PP \fBSET\fR \fIvar\fR \fIexpr\fR .PP \fIVar\fR is the name of a variable. It must start with a letter or underscore, and consist only of letters, digits and underscores. Only the first 12 characters of a variable name are significant. Variable names are \fInot\fR case sensitive; thus, "Afoo" and "afOo" are the same variable. Examples: .PP .nf SET a 10 + (9*8) SET b "This is a test" SET mydir getenv("HOME") SET time 12:15 SET date today() .fi .PP Note that variables themselves have no type. They take on the type of whatever you store in them. .PP To delete a variable, use the \fBUNSET\fR command: .PP \fBUNSET\fR \fIvar\fR [\fIvar\fR...] .PP For example, to delete all the variables declared above, use: .PP .nf UNSET a b mydir time date .fi .PP .B SYSTEM VARIABLES .PP In addition to the regular user variables, \fBRemind\fR has several "system variables" that are used to query or control the operating state of \fBRemind\fR. System variables are available starting from version 03.00.07 of \fBRemind\fR. .PP All system variables begin with a dollar sign '$'. They can be used in \fBSET\fR commands and expressions just as regular variables can. All system variables always hold values of a specified type. In addition, some system variables cannot be modified, and you cannot create new system variables. System variables can be initialized on the command line with the \fB\-i\fR option, but you may need to quote them to avoid having the shell interpret the dollar sign. System variable names are not case-sensitive. .PP The following system variables are defined. Those marked "read-only" cannot be changed with the \fBSET\fR command. All system variables hold values of type \fBINT\fR, unless otherwise specified. .TP .B $CalcUTC If 1 (the default), then \fBRemind\fR uses C library functions to calculate the number of minutes between local and Universal Time Coordinated. This affects astronomical calculations (\fBsunrise()\fR for example.) If 0, then you must supply the number of minutes between local and Universal Time Coordinated in the \fB$MinsFromUTC\fR system variable. .TP .B $CalMode (read-only) If non-zero, then the \fB\-c\fR option was supplied on the command line. .TP .B $Daemon (read-only) If the daemon mode \fB\-z\fR was invoked, contains the number of minutes between wakeups. If not running in daemon mode, contains 0. .TP .B $DateSep This variable can be set only to "/" or "-". It holds the character used to separate portions of a date when \fBRemind\fR prints a DATE or DATETIME value. .TP .B $DefaultPrio The default priority assigned to reminders without a \fBPRIORITY\fR clause. You can set this as required to adjust the priorities of blocks of reminders without having to type priorities for individual reminders. At startup, \fB$DefaultPrio\fR is set to 5000; it can range from 0 to 9999. .TP .B $DontFork (read-only) If non-zero, then the \fB\-c\fR option was supplied on the command line. .TP .B $DontTrigAts (read-only) The number of times that the \fB\-a\fR option was supplied on the command line. .TP .B $DontQueue (read-only) If non-zero, then the \fB\-q\fR option was supplied on the command line. .TP .B $EndSent (STRING type) Contains a list of characters that end a sentence. The \fBMSF\fR keyword inserts two spaces after these characters. Initially, \fB$EndSent\fR is set to ".!?" (period, exclamation mark, and question mark.) .TP .B $EndSentIg (STRING type) Contains a list of characters that should be ignored when \fBMSF\fR decides whether or not to place two spaces after a sentence. Initially, is set to "'>)]}"+CHAR(34) (single-quote, greater-than, right parenthesis, right bracket, right brace, and double-quote.) .PP .RS For example, the default values work as follows: .PP .nf MSF He said, "Huh! (Two spaces will follow this.)" Yup. .fi .PP because the final parenthesis and quote are ignored (for the purposes of spacing) when they follow a period. .RE .TP .B $FirstIndent The number of spaces by which to indent the first line of a \fBMSF\fR-type reminder. The default is 0. .TP .B $FoldYear The standard Unix library functions may have difficulty dealing with dates later than 2037. If this variable is set to 1, then the UTC calculations "fold back" years later than 2037 before using the Unix library functions. For example, to find out whether or not daylight saving time is in effect in June, 2077, the year is "folded back" to 2010, because both years begin on a Monday, and both are non-leapyears. The rules for daylight saving time are thus presumed to be identical for both years, and the Unix library functions can handle 2010. By default, this variable is 0. Set it to 1 if the sun or UTC functions misbehave for years greater than 2037. .TP .B $FormWidth The maximum width of each line of text for formatting \fBMSF\fR-type reminders. The default is 72. If an \fBMSF\fR-type reminder contains a word too long to fit in this width, it will not be truncated - the width limit will be ignored. .TP .B $HushMode (read-only) If non-zero, then the \fB\-h\fR option was supplied on the command line. .TP .B $IgnoreOnce (read-only) If non-zero, then the \fB\-o\fR option was supplied on the command line, or a date different from today's true date was supplied. If non-zero, then \fBONCE\fR directives will be ignored. .TP .B $InfDelta (read-only) If non-zero, then the \fB\-t\fR option was supplied on the command line. .TP .B $LatDeg, $LatMin, $LatSec These specify the latitude of your location. \fB$LatDeg\fR can range from \-90 to 90, and the others from \-59 to 59. Northern latitudes are positive; southern ones are negative. For southern latitudes, all three components should be negative. .TP .B $Location (STRING type) This is a string specifying the name of your location. It is usually the name of your town or city. It can be set to whatever you like, but good style indicates that it should be kept consistent with the latitude and longitude system variables. .TP .B $LongDeg, $LongMin, $LongSec These specify the longitude of your location. \fB$LongDeg\fR can range from \-180 to 180. Western longitudes are positive; eastern ones are negative. Note that all three components should have the same sign: All positive for Western longitudes and all negative for Eastern longitudes. .RS .PP The latitude and longitude information is required for the functions \fBsunrise()\fR and \fBsunset()\fR. Default values can be compiled into \fBRemind\fR, or you can \fBSET\fR the correct values at the start of your reminder scripts. .RE .TP .B $MaxSatIter The maximum number of iterations for the \fBSATISFY\fR clause (described later.) Must be at least 10. .TP .B $MinsFromUTC The number of minutes between Universal Time Coordinated and local time. If \fB$CalcUTC\fR is non-zero, this is calculated upon startup of \fBRemind\fR. Otherwise, you must set it explicitly. If \fB$CalcUTC\fR is zero, then \fB$MinsFromUTC\fR is used in the astronomical calculations. You must adjust it for daylight saving time yourself. Also, if you want to initialize \fB$MinsFromUTC\fR using the \fB\-i\fR command-line option, you must also set \fB$CalcUTC\fR to 0 with the \fB\-i\fR option. .TP .B $NextMode (read-only) If non-zero, then the \fB\-n\fR option was supplied on the command line. .TP .B $NumQueued (read-only) Contains the number of reminders queued so far for background timed triggering. .TP .B $NumTrig (read-only) Contains the number of reminders triggered for the current date. One use for this variable is as follows: Suppose you wish to shade in the box of a PostScript calendar whenever a holiday is triggered. You could save the value of \fB$NumTrig\fR in a regular variable prior to executing a block of holiday reminders. If the value of \fB$NumTrig\fR after the holiday block is greater than the saved value, then at least one holiday was triggered, and you can execute the command to shade in the calendar box. (See the section "Calendar Mode".) .PP .RS Note that \fB$NumTrig\fR is affected \fIonly\fR by \fBREM\fR commands; triggers in \fBIFTRIG\fR commands do not affect it. .RE .TP .B $PrefixLineNo (read-only) If non-zero, then the \fB\-l\fR option was supplied on the command line. .TP .B $PSCal (read-only) If non-zero, then the \fB\-p\fR option was supplied on the command line. .TP .B $RunOff (read-only) If non-zero, the \fBRUN\fR directives are disabled. .TP .B $SimpleCal (read-only) Set to a non-zero value if \fIeither\fR of the \fB\-p\fR or \fB\-s\fR command-line options was supplied. .TP .B $SortByDate (read-only) Set to 0 if no \fB\-g\fR option is used, 1 if sorting by date in ascending order, or 2 if sorting by date in descending order. .TP .B $SortByPrio (read-only) Set to 0 if no \fB\-g\fR option is used, 1 if sorting by priority in ascending order, or 2 if sorting by priority in descending order. .TP .B $SortByTime (read-only) Set to 0 if no \fB\-g\fR option is used, 1 if sorting by time in ascending order, or 2 if sorting by time in descending order. .TP .B $SubsIndent The number of spaces by which all lines (except the first) of an \fBMSF\fR-type reminder should be indented. The default is 0. .TP .B $T (read-only, DATE type) Exactly equivalent to \fBtrigdate()\fR. (See BUILT-IN FUNCTIONS.) .TP .B $Td (read-only) Equivalent to \fBday(trigdate())\fR. .TP .B $Tm (read-only) Equivalent to \fBmonnum(trigdate())\fR. .TP .B $Tw (read-only) Equivalent to \fBwkdaynum(trigdate())\fR. .TP .B $Ty (read-only) Equivalent to \fByear(trigdate())\fR. .TP .B $TimeSep This variable can be set only to ":" or ".". It holds the character used to separate portions of a time when \fBRemind\fR prints a TIME or DATETIME value. .TP .B $UntimedFirst (read-only) Set to 1 if the \fB\-g\fR option is used with a fourth sort character of "d"; set to 0 otherwise. .TP .B $U (read-only, DATE type) Exactly equivalent to \fBtoday()\fR. (See BUILT-IN FUNCTIONS.) .TP .B $Ud (read-only) Equivalent to \fBday(today())\fR. .TP .B $Um (read-only) Equivalent to \fBmonnum(today())\fR. .TP .B $Uw (read-only) Equivalent to \fBwkdaynum(today())\fR. .TP .B $Uy (read-only) Equivalent to \fByear(today())\fR. .PP Note: If any of the calendar modes are in effect, then the values of $Daemon, $DontFork, $DontTrigAts, $DontQueue, $HushMode, $IgnoreOnce, $InfDelta, and $NextMode are not meaningful. .PP .B BUILT-IN FUNCTIONS .PP \fBRemind\fR has a plethora of built-in functions. The syntax for a function call is the same as in C - the function name, followed a comma-separated list of arguments in parentheses. Function names are not case-sensitive. If a function takes no arguments, it must be followed by "()" in the function call. Otherwise, \fBRemind\fR will interpret it as a variable name, and probably not work correctly. .PP In the descriptions below, short forms are used to denote acceptable types for the arguments. The characters "i", "s", "d", "t" and "q" denote \fBINT\fR, \fBSTRING\fR, \fBDATE\fR, \fBTIME\fR and \fBDATETIME\fR arguments, respectively. If an argument can be one of several types, the characters are concatenated. For example, "di_arg" denotes an argument that can be a \fBDATE\fR or an \fBINT\fR. "x_arg" denotes an argument that can be of any type. The type of the argument is followed by an underscore and an identifier naming the argument. .PP The built-in functions are: .TP .B abs(i_num) Returns the absolute value of \fInum\fR. .TP .B access(s_file, si_mode) Tests the access permissions for the file \fIfile\fR. \fIMode\fR can be a string, containing a mix of the characters "rwx" for read, write and execute permission testing. Alternatively, \fImode\fR can be a number as described in the UNIX \fBaccess\fR(2) system call. The function returns 0 if the file can be accessed with the specified \fImode\fR, and \-1 otherwise. .TP .B args(s_fname) Returns the number of arguments expected by the user-defined function \fIfname\fR, or \-1 if no such user-defined function exists. Note that this function examines only user-defined functions, not built-in functions. Its main use is to determine whether or not a particular user-defined function has been defined previously. The \fBargs()\fR function is available only in versions of \fBRemind\fR from 03.00.04 and up. .TP .B asc(s_string) Returns an \fBINT\fR that is the ASCII code of the first character in \fIstring\fR. As a special case, \fBasc("")\fR returns 0. .TP .B baseyr() Returns the "base year" that was compiled into \fBRemind\fR (normally 1990.) All dates are stored internally as the number of days since 1 January of \fBbaseyr()\fR. .TP .B char(i_i1 [,i_i2...]) This function can take any number of \fBINT\fR arguments. It returns a \fBSTRING\fR consisting of the characters specified by the arguments. Note that none of the arguments can be 0, unless there is only one argument. As a special case, \fBchar(0)\fR returns "". .PP .RS Note that because \fBRemind\fR does not support escaping of characters in strings, the only way to get a double-quote in a string is to use \fBchar(34)\fR. .RE .TP .B choose(i_index, x_arg1 [,x_arg2...]) \fBChoose\fR must take at least two arguments, the first of which is an \fBINT\fR. If \fIindex\fR is \fIn\fR, then the \fIn\fRth subsequent argument is returned. If \fIindex\fR is less than 1, then \fIarg1\fR is returned. If \fIindex\fR is greater than the number of subsequent arguments, then the last argument is returned. Examples: .PP .nf \fBchoose(0, "foo", 1:13, 1000)\fR returns "foo" \fBchoose(1, "foo", 1:13, 1000)\fR returns "foo" \fBchoose(2, "foo", 1:13, 1000)\fR returns 1:13 \fBchoose(3, "foo", 1:13, 1000)\fR returns 1000 \fBchoose(4, "foo", 1:13, 1000)\fR returns 1000 .fi .RS Note that all arguments to \fBchoose()\fR are \fIalways\fR evaluated. .RE .TP .B coerce(s_type, x_arg) This function converts \fIarg\fR to the specified \fItype\fR, if such conversion is possible. \fIType\fR must be one of "INT", "STRING", "DATE", "TIME" or "DATETIME" (case-insensitive). The conversion rules are as follows: .RS .PP If \fIarg\fR is already of the \fItype\fR specified, it is returned unchanged. .PP If \fItype\fR is "STRING", then \fIarg\fR is converted to a string consisting of its printed representation. .PP If \fItype\fR is "DATE", then an \fBINT\fR \fIarg\fR is converted by interpreting it as the number of days since 1 January \fBbaseyr()\fR. A \fBSTRING\fR \fIarg\fR is converted by attempting to read it as if it were a printed date. A \fBDATETIME\fR is converted to a date by dropping the time component. A \fBTIME\fR \fIarg\fR cannot be converted to a date. .PP If \fItype\fR is "TIME", then an \fBINT\fR \fIarg\fR is converted by interpreting it as the number of minutes since midnight. A \fBSTRING\fR \fIarg\fR is converted by attempting to read it as if it were a printed time. A \fBDATETIME\fR is converted to a time by dropping the date component. A \fBDATE\fR \fIarg\fR cannot be converted to a time. .PP If \fItype\fR is "DATETIME", then an \fBINT\fR \fIarg\fR is converted by interpreting it as the number of minutes since midnight, 1 January \fBbaseyr()\fR. A \fBSTRING\fR is converted by attempting to read it as if it were a printed datetime. Other types cannot be converted to a datetime. .PP If \fItype\fR is "INT", then \fBDATE\fR, \fBTIME\fR and \fBDATETIME\fR arguments are converted using the reverse of procedures described above. A \fBSTRING\fR \fIarg\fR is converted by parsing it as an integer. .RE .TP .B current() Returns the current date and time as a DATETIME object. This may be the actual date and time, or may be the date and time supplied on the command line. .TP .B date(i_y, i_m, i_d) The \fBdate()\fR function returns a \fBDATE\fR object with the year, month and day components specified by \fIy\fR, \fIm\fR and \fId\fR. .TP .B datepart(dq_datetime) Returns a \fBDATE\fR object representing the date portion of \fIdatetime\fR. .TP .B datetime(args) The \fBdatetime()\fR function can take anywhere from two to five arguments. It always returns a DATETIME generated from its arguments. .RS .PP If you supply two arguments, the first must be a DATE and the second a TIME. .PP If you supply three arguments, the first must be a DATE and the second and third must be INTs. The second and third arguments are interpreted as hours and minutes and converted to a TIME. .PP If you supply four arguments, the first three must be INTs, interpreted as the year, month and day. The fourth argument must be a TIME. .PP Finally, if you supply five arguments, they must all be INTs and are interpreted as year, month, day, hour and minute. .RE .TP .B dawn([dq_date]) Returns the time of "civil dawn" on the specified \fIdate\fR. If \fIdate\fR is omitted, defaults to \fBtoday()\fR. If a \fIdatetime\fR object is supplied, only the date component is used. .TP .B day(dq_date) This function takes a \fBDATE\fR or \fBDATETIME\fR as an argument, and returns an \fBINT\fR that is the day-of-month component of \fIdate\fR. .TP .B daysinmon(i_m, i_y) Returns the number of days in month \fIm\fR (1-12) of the year \fIy\fR. .TP .B defined(s_var) Returns 1 if the variable named by \fIvar\fR is defined, or 0 if it is not. .RS Note that \fBdefined()\fR takes a \fBSTRING\fR argument; thus, to check if variable X is defined, use: .PP .nf defined("X") .fi .PP and not: .PP .nf defined(X) .fi .PP The second example will attempt to evaluate X, and will return an error if it is undefined or not of type \fBSTRING\fR. .RE .TP .B dosubst(s_str [,d_date [,t_time]]) \fRor\fB dosubst(s_str [,q_datetime]) Returns a \fBSTRING\fR that is the result of passing \fIstr\fR through the substitution filter described earlier. The parameters \fIdate\fR and \fItime\fR (or \fIdatetime\fR) establish the effective trigger date and time used by the substitution filter. If \fIdate\fR and \fItime\fR are omitted, they default to \fBtoday()\fR and \fBnow()\fR. .RS .PP Note that if \fIstr\fR does not end with "%", a newline character will be added to the end of the result. Also, calling \fBdosubst()\fR with a \fIdate\fR that is in the past (i.e., if \fIdate\fR < \fBtoday()\fR) will produce undefined results. .PP \fBDosubst()\fR is only available starting from version 03.00.04 of \fBRemind\fR. .RE .TP .B dusk([dq_date]) Returns the time of "civil twilight" on the specified \fIdate\fR. If \fIdate\fR is omitted, defaults to \fBtoday()\fR. .TP .B easterdate(dqi_arg) If \fIarg\fR is an \fBINT\fR, then returns the date of Easter Sunday for the specified year. If \fIarg\fR is a \fBDATE\fR or \fBDATETIME\fR, then returns the date of the next Easter Sunday on or after \fIarg\fR. (The time component of a datetime is ignored.) .TP .B evaltrig(s_trigger [,dq_start]) Evaluates \fItrigger\fR as if it were a REM or IFTRIG trigger specification and returns the trigger date as a \fBDATE\fR (or as a \fBDATETIME\fR if there is an \fBAT\fR clause.) Returns a negative \fBINT\fR if no trigger could be computed. .RS .PP Normally, \fBevaltrig\fR finds a trigger date on or after today. If you supply the \fIstart\fR argument, then it scans starting from there. .PP For example, the expression: .PP .nf evaltrig("Mon 1", '2008-10-07') .fi .PP returns '2008-11-03', since that is the first date on or after 7 October 2008 that satisfies "Mon 1". .PP If you want to see how many days it is from the first Monday in October, 2008 to the first Monday in November, 2008, use: .PP .nf evaltrig("Mon 1", '2008-11-01') - evaltrig("Mon 1", '2008-10-01') .fi .PP and the answer is 28. The trigger argument to \fBevaltrig\fR can have all the usual trigger clauses (\fBOMIT\fR, \fBAT\fR, \fBSKIP\fR, etc.) but \fIcannot\fR have a \fBSATISFY\fR, \fBMSG\fR, etc. reminder-type clause. .RE .TP .B filedate(s_filename) Returns the modification date of \fIfilename\fR. If \fIfilename\fR does not exist, or its modification date is before the year \fBbaseyr()\fR, then 1 January of \fBbaseyr()\fR is returned. .TP .B filedatetime(s_filename) Returns the modification date and time of \fIfilename\fR. If \fIfilename\fR does not exist, or its modification date is before the year \fBbaseyr()\fR, then midnight, 1 January of \fBbaseyr()\fR is returned. .TP .B filedir() Returns the directory that contains the current file being processed. It may be a relative or absolute pathname, but is guaranteed to be correct for use in an \fBINCLUDE\fR command as follows: .PP .nf INCLUDE [filedir()]/stuff .fi .PP .RS This includes the file "stuff" in the same directory as the current file being processed. .RE .TP .B filename() Returns (as a \fBSTRING\fR) the name of the current file being processed by \fBRemind\fR. Inside included files, returns the name of the included file. .TP .B getenv(s_envvar) Similar to the \fBgetenv\fR(2) system call. Returns a string representing the value of the specified environment variable. Returns "" if the environment variable is not defined. Note that the names of environment variables are generally case-sensitive; thus, getenv("HOME") is not the same as getenv("home"). .TP .B hebdate(i_day, s_hebmon [,idq_yrstart [,i_jahr [,i_aflag]]]) Support for Hebrew dates - see the section "The Hebrew Calendar" .TP .B hebday(dq_date) Support for Hebrew dates - see the section "The Hebrew Calendar" .TP .B hebmon(dq_date) Support for Hebrew dates - see the section "The Hebrew Calendar" .TP .B hebyear(dq_date) Support for Hebrew dates - see the section "The Hebrew Calendar" .TP .B hour(tq_time) Returns the hour component of \fItime\fR. .TP .B iif(si_test1, x_arg1, [si_test2, x_arg2,...], x_default) If \fItest1\fR is not zero or the null string, returns \fIarg1\fR. Otherwise, if \fItest2\fR is not zero or the null string, returns \fIarg2\fR, and so on. If all of the \fItest\fR arguments are false, returns \fIdefault\fR. Note that all arguments are \fIalways\fR evaluated. This function accepts an odd number of arguments - note that prior to version 03.00.05 of \fBRemind\fR, it accepted 3 arguments only. The 3-argument version of \fBiif()\fR is compatible with previous versions of \fBRemind\fR. .TP .B index(s_search, s_target [,i_start) Returns an \fBINT\fR that is the location of \fItarget\fR in the string \fIsearch\fR. The first character of a string is numbered 1. If \fItarget\fR does not exist in \fIsearch\fR, then 0 is returned. .RS .PP The optional parameter \fIstart\fR specifies the position in \fIsearch\fR at which to start looking for \fItarget\fR. .RE .TP .B isdst([d_date [,t_time]]) \fRor\fB isdst(q_datetime) Returns a positive number if daylight saving time is in effect on the specified date and time. \fIDate\fR defaults to \fBtoday()\fR and \fItime\fR defaults to midnight. .RS .PP Note that this function is only as reliable as the C run-time library functions. It is available starting with version 03.00.07 of \fBRemind\fR. .RE .TP .B isleap(idq_arg) Returns 1 if \fIarg\fR is a leap year, and 0 otherwise. \fIArg\fR can be an \fBINT\fR, \fBDATE\fR or \fBDATETIME\fR object. If a \fBDATE\fR or \fBDATETIME\fR is supplied, then the year component is used in the test. .TP .B isomitted(dq_date) Returns 1 if \fIdate\fR is omitted, given the current global \fBOMIT\fR context. Returns 0 otherwise. (If a datetime is supplied, only the date part is used.) Note that any local \fBOMIT\fR or \fBOMITFUNC\fR clauses are \fInot\fR taken into account by this function. .TP .B language() Returns a \fBSTRING\fR naming the language supported by \fBRemind\fR. (See "Foreign Language Support.") By default, \fBRemind\fR is compiled to support English messages, so this function returns "English". For other languages, this function will return the English name of the language (e.g. "German") Note that \fBlanguage()\fR is not available in versions of \fBRemind\fR prior to 03.00.02. .TP .B lower(s_string) Returns a \fBSTRING\fR with all upper-case characters in \fIstring\fR converted to lower-case. .TP .B max(x_arg1 [,x_arg2...) Can take any number of arguments, and returns the maximum. The arguments can be of any type, but must all be of the same type. They are compared as with the > operator. .TP .B min(x_arg1 [,x_arg2...) Can take any number of arguments, and returns the minimum. The arguments can be of any type, but must all be of the same type. They are compared as with the < operator. .TP .B minsfromutc([d_date [,t_time]]) \fRor\fB minsfromutc(q_datetime) Returns the number of minutes from Universal Time Coordinated (formerly GMT) to local time on the specified date and time. \fIDate\fR defaults to \fBtoday()\fR and \fItime\fR defaults to midnight. If local time is before UTC, the result is negative. Otherwise, the result is positive. .RS .PP Note that this function is only as reliable as the C run-time library functions. It is available starting with version 03.00.07 of \fBRemind\fR. .RE .TP .B minute(tq_time) Returns the minute component of \fItime\fR. .TP .B mon(dqi_arg) If \fIarg\fR is of \fBDATE\fR or \fBDATETIME\fR type, returns a string that names the month component of the date. If \fIarg\fR is an \fBINT\fR from 1 to 12, returns a string that names the month. .TP .B monnum(dq_date) Returns an \fBINT\fR from 1 to 12, representing the month component of \fIdate\fR. .TP .B moondate(i_phase [,d_date [,t_time]]) \fRor\fB moondate(i_phase, q_datetime) This function returns the date of the first occurrence of the phase \fIphase\fR of the moon on or after \fIdate\fR and \fItime\fR. \fIPhase\fR can range from 0 to 3, with 0 signifying new moon, 1 first quarter, 2 full moon, and 3 third quarter. If \fIdate\fR is omitted, it defaults to \fBtoday()\fR. If \fItime\fR is omitted, it defaults to midnight. .RS .PP For example, the following returns the date of the next full moon: .PP .nf SET fullmoon moondate(2) .fi .PP .RE .TP .B moontime(i_phase [,d_date [,t_time]]) \fRor\fB moontime(i_phase, q_datetime) This function returns the time of the first occurrence of the phase \fIphase\fR of the moon on or after \fIdate\fR and \fItime\fR. \fIPhase\fR can range from 0 to 3, with 0 signifying new moon, 1 first quarter, 2 full moon, and 3 third quarter. If \fIdate\fR is omitted, it defaults to \fBtoday()\fR. If \fItime\fR is omitted, it defaults to midnight. \fBMoontime()\fR is intended to be used in conjunction with \fBmoondate()\fR. The \fBmoondate()\fR and \fBmoontime()\fR functions are accurate to within a couple of minutes of the times in "Old Farmer's Almanac" for Ottawa, Ontario. .RS .PP For example, the following returns the date and time of the next full moon: .PP .nf MSG Next full moon at [moontime(2)] on [moondate(2)] .fi .PP .RE .TP .B moondatetime(i_phase [,d_date [,t_time]]) \fRor\fB moondatetime(i_phase, q_datetime) This function is similar to \fBmoondate\fR and \fBmoontime\fR, but returns a DATETIME result. .TP .B moonphase([d_date [,t_time]]) \fRor\fB moonphase(q_datetime) This function returns the phase of the moon on \fIdate\fR and \fItime\fR, which default to \fBtoday()\fR and midnight, respectively. The returned value is an integer from 0 to 359, representing the phase of the moon in degrees. 0 is a new moon, 180 is a full moon, 90 is first-quarter, etc. .TP .B nonomitted(dq_start, dq_end [,s_wkday...]) This function returns the number of \fInon-\fRomitted days between \fIstart\fR and \fIend\fR. If \fIstart\fR is non-omitted, then it is counted. \fIend\fR is never counted. .RS .PP Note that \fIend\fR must be greater than or equal to \fIstart\fR or an error is reported. In addition to using the global OMIT context, you can supply additional arguments that are names of weekdays to be omitted. However, in a \fBREM\fR command, any local \fBOMITFUNC\fR clause is \fInot\fR taken into account by this function. .PP For example, the following line sets a to 11 (assuming no global OMITs): .PP .nf set a nonomitted('2007-08-01', '2007-08-16', "Sat", "Sun") .fi .PP because Thursday, 16 August 2007 is the 11th working day (not counting Saturday and Sunday) after Wednesday, 1 August 2007. .PP \fBnonomitted\fR has various uses. For example, many schools run on a six-day cycle and the day number is not incremented on holidays. Suppose the school year starts with Day 1 on 4 September 2007. The following reminder will label day numbers in a calendar: .PP .nf IF today() >= '2007-09-04' set daynum nonomitted('2007-09-04', today(), "Sat", "Sun") REM OMIT SAT SUN SKIP CAL Day [(daynum % 6) + 1] ENDIF .fi .PP Obviously, the answer you get from \fBnonomitted\fR depends on the global OMIT context. If you use moveable OMITs, you may get inconsistent results. .PP Here is a more complex use for \fBnonomitted\fR. My garbage collection follows two interleaved 14-day cycles: One Friday, garbage and paper recycling ("Black Box") are collected. The next Friday, garbage and plastic recycling ("Blue Box") are collected. If any of Monday-Friday is a holiday, collection is delayed until the Saturday. Here's a way to encode these rules: .PP .nf fset _garbhol(x) wkdaynum(x) == 5 && nonomitted(x-4, x+1) < 5 REM 12 November 1999 *14 AFTER OMITFUNC _garbhol MSG Black Box REM 19 November 1999 *14 AFTER OMITFUNC _garbhol MSG Blue Box .fi .PP Here's how it works: The _garbhol(x) user-defined function returns 1 if and only if (1) \fIx\fR is a Friday and (2) there is at least one OMITted day from the previous Monday up to and including the Friday. .PP The first REM statement sets up the 14-day black-box cycle. The AFTER keyword makes it move collection to the Saturday if _garbhol returns 1. The second REM statement sets up the 14-day blue-box cycle with a similar adjustment made by AFTER in conjunction with _garbhol. .RE .TP .B now() Returns the current system time, as a \fBTIME\fR type. This may be the actual time, or a time supplied on the command line. .TP .B ord(i_num) Returns a string that is the ordinal number \fInum\fR. For example, \fBord(2)\fR returns "2nd", and \fBord(213)\fR returns "213th". .TP .B ostype() Returns "UNIX". Remind used to run on OS/2 and MS-DOS, but does not any longer. .TP .B plural(i_num [,s_str1 [,s_str2]]) Can take from one to three arguments. If one argument is supplied, returns "s" if \fInum\fR is not 1, and "" if \fInum\fR is 1. .RS .PP If two arguments are supplied, returns \fIstr1\fR + "s" if \fInum\fR is not 1. Otherwise, returns \fIstr1\fR. .PP If three arguments are supplied, returns \fIstr1\fR if \fInum\fR is 1, and \fIstr2\fR otherwise. .RE .TP .B psmoon(i_phase [,i_size [,s_note [,i_notesize]]]) [DEPRECATED] Returns a \fBSTRING\fR consisting of PostScript code to draw a moon in the upper-left hand corner of the calendar box. \fIPhase\fR specifies the phase of the moon, and is 0 (new moon), 1 (first quarter), 2 (full moon) or 3 (third quarter). If \fIsize\fR is specified, it controls the radius of the moon in PostScript units (1/72 inch.) If it is not specified or is negative, the size of the day-number font is used. .PP .PP .RS For example, the following four lines place moon symbols on the PostScript calendar: .PP .nf REM [moondate(0)] PS [psmoon(0)] REM [moondate(1)] PS [psmoon(1)] REM [moondate(2)] PS [psmoon(2)] REM [moondate(3)] PS [psmoon(3)] .fi .PP If \fInote\fR is specified, the text is used to annotate the moon display. The font is the same font used for calendar entries. If \fInotesize\fR is given, it specifies the font size to use for the annotation, in PostScript units (1/72 inch.) If \fInotesize\fR is not given, it defaults to the size used for calendar entries. (If you annotate the display, be careful not to overwrite the day number -- \fBRemind\fR does not check for this.) For example, if you want the time of each new moon displayed, you could use this in your reminder script: .PP .nf REM [moondate(0)] PS [psmoon(0, \-1, moontime(0)+"")] .fi .PP Note how the time is coerced to a string by concatenating the null string. .RE .TP \fBpsshade(i_gray)\fR or \fBpsshade(i_red, i_green, i_blue)\fR [DEPRECATED] Returns a \fBSTRING\fR that consists of PostScript commands to shade a calendar box. \fINum\fR can range from 0 (completely black) to 100 (completely white.) If three arguments are given, they specify red, green and blue intensity from 0 to 100. Here's an example of how to use this: .RS .PP .nf REM Sat Sun PS [psshade(95)] .fi .PP The above command emits PostScript code to lightly shade the boxes for Saturday and Sunday in a PostScript calendar. .PP Note that \fBpsmoon\fR and \fBpsshade\fR are deprecated; instead you should use the SPECIAL SHADE and SPECIAL MOON reminders as described in "Out-of-Band Reminders." .RE .TP .B realcurrent() Returns (as a DATETIME) the true date and time of day as provided by the operating system. This is in contrast to \fBcurrent()\fR, which may return a time supplied on the command line. .TP .B realnow() Returns the true time of day as provided by the operating system. This is in contrast to \fBnow()\fR, which may return a time supplied on the command line. .TP .B realtoday() Returns the date as provided by the operating system. This is in contrast to \fBRemind\fR's concept of "today", which may be changed if it is running in calendar mode, or if a date has been supplied on the command line. .TP .B sgn(i_num) Returns \-1 if \fInum\fR is negative, 1 if \fInum\fR is positive, and 0 if \fInum\fR is zero. .TP .B shell(s_cmd [,i_maxlen]) Executes \fIcmd\fR as a system command, and returns the first 511 characters of output resulting from \fIcmd\fR. Any whitespace character in the output is converted to a space. Note that if \fBRUN OFF\fR has been executed, or the \fB\-r\fR command-line option has been used, \fBshell()\fR will result in an error, and \fIcmd\fR will not be executed. .RS .PP If \fImaxlen\fR is specified, then \fBshell()\fR returns the first \fImaxlen\fR characters of output (rather than the first 511). If \fImaxlen\fR is specified as a negative number, then \fIall\fR the output from \fIcmd\fR is returned. .RE .TP .B slide(d_start, i_amt [,s_wkday...]) This function is the inverse of \fBnonomitted\fR. It adds \fIamt\fR days (which can be negative) to \fIstart\fR, \fInot counting omitted days\fR. The optional \fIwkday\fR arguments are additional weekday names to omit. .RS .PP Consider this example: .PP .nf OMIT 14 May 2009 SET a slide('2009-05-13', 5, "Sat", "Sun") .fi .PP In this case, \fIa\fR is set to 2009-05-21. That's because we slide forward by 5 days, not including Thursday, May 14 or Saturday and Sunday, May 16 and 17. You can go backwards, too, so: .PP .nf OMIT 14 May 2009 SET a slide('2009-05-21', \-5, "Sat", "Sun") .fi .PP takes \fIa\fR back to 2009-05-13. .RE .TP .B strlen(s_str) Returns the length of \fIstr\fR. .TP .B substr(s_str, i_start [,i_end]) Returns a \fBSTRING\fR consisting of all characters in \fIstr\fR from \fIstart\fR up to and including \fIend\fR. Characters are numbered from 1. If \fIend\fR is not supplied, then it defaults to the length of \fIstr\fR. .TP .B sunrise([dq_date]) Returns a \fBTIME\fR indicating the time of sunrise on the specified \fIdate\fR (default \fBtoday()\fR.) In high latitudes, there may be no sunrise on a particular day, in which case \fBsunrise()\fR returns the \fBINT\fR 0 if the sun never sets, or 1440 if it never rises. .TP .B sunset([dq_date]) Returns a \fBTIME\fR indicating the time of sunset on the specified \fIdate\fR (default \fBtoday()\fR.) In high latitudes, there may be no sunset on a particular day, in which case \fBsunset()\fR returns the \fBINT\fR 0 if the sun never rises, or 1440 if it never sets. .RS .PP The functions \fBsunrise()\fR and \fBsunset()\fR are based on an algorithm in "Almanac for Computers for the year 1978" by L. E. Doggett, Nautical Almanac Office, USNO. They require the latitude and longitude to be specified by setting the appropriate system variables. (See "System Variables".) The sun functions should be accurate to within about 4 minutes for latitudes lower than 60 degrees. The functions are available starting from version 03.00.07 of \fBRemind\fR. .RE .TP .B time(i_hr, i_min) Creates a \fBTIME\fR with the hour and minute components specified by \fIhr\fR and \fImin\fR. .TP .B timepart(tq_datetime) Returns a \fBTIME\fR object representing the time portion of \fIdatetime\fR. .TP .B today() Returns \fBRemind\fR's notion of "today." This may be the actual system date, or a date supplied on the command line, or the date of the calendar entry currently being computed. .TP .B trigdate() Returns the calculated trigger date of the last \fBREM\fR or \fBIFTRIG\fR command. If used in the \fIbody\fR of a \fBREM\fR command, returns that command's trigger date. If the most recent \fBREM\fR command did not yield a computable trigger date, returns the integer 0. .TP .B trigdatetime() Similar to trigdate(), but returns a \fBDATETIME\fR if the most recent triggerable \fBREM\fR command had an \fBAT\fR clause. If there was no \fBAT\fR clause, returns a \fBDATE\fR. If no trigger could be computed, returns the integer 0. .TP .B trigger(d_date [,t_time [,i_utcflag]]) \fRor\fB trigger(q_datetime [,i_utcflag]) Returns a string suitable for use in a \fBREM\fR command or a SCANFROM or UNTIL clause, allowing you to calculate trigger dates in advance. Note that in earlier versions of \fBRemind\fR, \fBtrigger\fR was required to convert a date into something the \fBREM\fR command could consume. However, in this version of \fBRemind\fR, you can omit it. Note that \fBtrigger()\fR \fIalways\fR returns its result in English, even for foreign-language versions of \fBRemind\fR. This is to avoid problems with certain C libraries that do not handle accented characters properly. Normally, the \fIdate\fR and \fItime\fR are the local date and time; however, if \fIutcflag\fR is non-zero, the \fIdate\fR and \fItime\fR are interpreted as UTC times, and are converted to local time. Examples: .RS .PP trigger('1993/04/01') .PP returns "1 April 1993", .PP trigger('1994/08/09', 12:33) .PP returns "9 August 1994 AT 12:33", as does: .PP trigger('1994/08/09@12:33'). .PP Finally: .PP trigger('1994/12/01', 03:00, 1) .PP returns "30 November 1994 AT 22:00" for EST, which is 5 hours behind UTC. The value for your time zone may differ. .RE .TP .B trigtime() Returns the time of the last \fBREM\fR command with an \fBAT\fR clause. If the last \fBREM\fR did not have an \fBAT\fR clause, returns the integer 0. .TP .B trigvalid() Returns 1 if the value returned by \fBtrigdate()\fR is valid for the most recent \fBREM\fR command, or 0 otherwise. Sometimes \fBREM\fR commands cannot calculate a trigger date. For example, the following \fBREM\fR command can never be triggered: .PP .nf REM Mon OMIT Mon SKIP MSG Impossible! .fi .PP .TP .B typeof(x_arg) Returns "STRING", "INT", "DATE", "TIME" or "DATETIME", depending on the type of \fIarg\fR. .TP .B tzconvert(q_datetime, s_srczone [,s_dstzone]) Converts \fBdatetime\fR from the time zone named by \fBsrczone\fR to the time zone named by \fBdstzone\fR. If \fBdstzone\fR is omitted, the default system time zone is used. The return value is a DATETIME. Time zone names are system-dependent; consult your operating system for legal values. Here is an example: .PP .nf tzconvert('2007-07-08@01:14', "Canada/Eastern", "Canada/Pacific") returns 2007-07-07@22:14 .fi .PP .TP .B upper(s_string) Returns a \fBSTRING\fR with all lower-case characters in \fIstring\fR converted to upper-case. .TP .B value(s_varname [,x_default]) Returns the value of the specified variable. For example, value("X"+"Y") returns the value of variable XY, if it is defined. If XY is not defined, an error results. .RS .PP However, if you supply a second argument, it is returned if the \fIvarname\fR is not defined. The expression value("XY", 0) will return 0 if XY is not defined, and the value of XY if it is defined. .RE .TP .B version() Returns a string specifying the version of \fBRemind\fR. For version 03.00.04, returns "03.00.04". It is guaranteed that as new versions of \fBRemind\fR are released, the value returned by \fBversion()\fR will strictly increase, according to the rules for string ordering. .TP .B weekno([dq_date, [i_wkstart, [i_daystart]]]) Returns the week number of the year. If no arguments are supplied, returns the ISO 8601 week number for \fBtoday()\fR. If one argument \fIdate\fR is supplied, then returns the ISO 8601 week number for that date. If two arguments are supplied, then \fIwkstart\fR must range from 0 to 6, and represents the first day of the week (with 0 being Sunday and 6 being Saturday.). If \fIwkstart\fR is not supplied, then it defaults to 1. If the third argument \fIdaystart\fR is supplied, then it specifies when Week 1 starts. If \fIdaystart\fR is less than or equal to 7, then Week 1 starts on the first \fIwkstart\fR on or after January \fIdaystart\fR. Otherwise, Week 1 starts on the first \fIwkstart\fR on or after December \fIdaystart\fR. If omitted, \fIdaystart\fR defaults to 29 (following the ISO 8601 definition.) .TP .B wkday(dqi_arg) If \fIarg\fR is a \fBDATE\fR or \fBDATETIME\fR, returns a string representing the day of the week of the date. If \fIarg\fR is an \fBINT\fR from 0 to 6, returns the corresponding weekday ("Sunday" to "Saturday"). .TP .B wkdaynum(dq_date) Returns a number from 0 to 6 representing the day-of-week of the specified \fIdate\fR. (0 represents Sunday, and 6 represents Saturday.) .TP .B year(dq_date) Returns a \fBINT\fR that is the year component of \fIdate\fR. .SH EXPRESSION PASTING .PP An extremely powerful feature of \fBRemind\fR is its macro capability, or "expression pasting." .PP In almost any situation where \fBRemind\fR is not expecting an expression, you can "paste" an expression in. To do this, surround the expression with square brackets. For example: .PP .nf REM [mydate] MSG foo .fi .PP This evaluates the expression "mydate", where "mydate" is presumably some pre-computed variable, and then "pastes" the result into the command-line for the parser to process. .PP A formal description of this is: When \fBRemind\fR encounters a "pasted-in" expression, it evaluates the expression, and coerces the result to a \fBSTRING\fR. It then substitutes the string for the pasted-in expression, and continues parsing. Note, however, that expressions are evaluated only once, not recursively. Thus, writing: .PP .nf ["[a+b]"] .fi .PP causes \fBRemind\fR to read the token "[a+b]". It does not interpret this as a pasted-in expression. In fact, the only way to get a literal left-bracket into a reminder is to use ["["]. .PP You can use expression pasting almost anywhere. However, there are a few exceptions: .TP o If \fBRemind\fR is expecting an expression, as in the \fBSET\fR command, or the \fBIF\fR command, you should \fBnot\fR include square brackets. For example, use: .PP .nf SET a 4+5 .fi and not: .nf SET a [4+5] .fi .TP o You cannot use expression pasting for the first token on a line. For example, the following will not work: .PP .nf ["SET"] a 1 .fi .RS .PP This restriction is because \fBRemind\fR must be able to unambiguously determine the first token of a line for the flow-control commands (to be discussed later.) .PP In fact, if \fBRemind\fR cannot determine the first token on a line, it assumes that it is a \fBREM\fR command. If expression-pasting is used, \fBRemind\fR assumes it is a \fBREM\fR command. Thus, the following three commands are equivalent: .PP .nf REM 12 Nov 1993 AT 13:05 MSG BOO! 12 Nov 1993 AT 13:05 MSG BOO! [12] ["Nov " + 1993] AT [12:05+60] MSG BOO! .fi .RE .TP o You cannot use expression-pasting to determine the type (\fBMSG\fR, \fBCAL\fR, etc.) of a \fBREM\fR command. You can paste expressions before and after the \fBMSG\fR, etc keywords, but cannot do something like this: .PP .nf REM ["12 Nov 1993 AT 13:05 " + "MSG" + " BOO!"] .fi .PP .B COMMON PITFALLS IN EXPRESSION PASTING .PP Remember, when pasting in expressions, that extra spaces are not inserted. Thus, something like: .PP .nf REM[expr]MSG[expr] .fi .PP will probably fail. .PP If you use an expression to calculate a \fIdelta\fR or \fIback\fR, ensure that the result is a positive number. Something like: .PP .nf REM +[mydelta] Nov 12 1993 MSG foo .fi .PP will fail if \fImydelta\fR happens to be negative. .PP .SH FLOW CONTROL COMMANDS .PP \fBRemind\fR has commands that control the flow of a reminder script. Normally, reminder scripts are processed sequentially. However, \fBIF\fR and related commands allow you to process files conditionally, and skip sections that you don't want interpreted. .PP .B THE IF COMMAND .PP The \fBIF\fR command has the following form: .PP .nf IF expr t-command t-command... ELSE f-command f-command... ENDIF .fi .PP Note that the commands are shown indented for clarity. Also, the \fBELSE\fR portion can be omitted. \fBIF\fR commands can be nested up to a small limit, probably around 8 or 16 levels of nesting, depending on your system. .PP If the \fIexpr\fR evaluates to a non-zero \fBINT\fR, or a non-null \fBSTRING\fR, then the \fBIF\fR portion is considered true, and the \fIt-commands\fR are executed. If \fIexpr\fR evaluates to zero or null, then the \fIf-commands\fR (if the \fBELSE\fR portion is present) are executed. If \fIexpr\fR is not of type \fBINT\fR or \fBSTRING\fR, then it is an error. .PP Examples: .PP .nf IF defined("want_hols") INCLUDE /usr/share/remind/holidays ENDIF IF today() > '1992/2/10' set missed_ap "You missed it!" ELSE set missed_ap "Still have time..." ENDIF .fi .PP .B THE IFTRIG COMMAND .PP The \fBIFTRIG\fR command is similar to an \fBIF\fR command, except that it computes a trigger (as in the \fBREM\fR command), and evaluates to true if a corresponding \fBREM\fR command would trigger. Examples: .PP .nf IFTRIG 1 Nov ; Executed on 1 Nov ELSE ; Executed except on 1 Nov ENDIF IFTRIG 1 \-1 OMIT Sat Sun +4 ; Executed on last working day of month, ; and the 4 working days preceding it ELSE ; Executed except on above days ENDIF .fi .PP Note that the \fBIFTRIG\fR command computes a trigger date, which can be retrieved with the \fBtrigdate()\fR function. You can use all of the normal trigger components, such as \fBUNTIL\fR, \fIdelta\fR, etc in the \fBIFTRIG\fR command. .PP .SH USER-DEFINED FUNCTIONS .PP In addition to the built-in functions, \fBRemind\fR allows you to define your own functions. The \fBFSET\fR command does this for you: .PP \fBFSET\fR \fIfname\fR(\fIargs\fR) \fIexpr\fR .PP \fIFname\fR is the name of the function, and follows the convention for naming variables. \fIArgs\fR is a comma-separated list of arguments, and \fIexpr\fR is an expression. \fIArgs\fR can be empty, in which case you define a function taking no parameters. Here are some examples: .PP .nf FSET double(x) 2*x FSET yeardiff(date1, date2) year(date1) - year(date2) FSET since(x) ord(year(trigdate())\-x) .fi .PP The last function is useful in birthday reminders. For example: .PP .nf REM 1 Nov +12 MSG Dean's [since(1984)] birthday is %b. .fi .PP Dean was born in 1984. The above example, on 1 November 1992, would print: .PP .nf Dean's 8th birthday is today. .fi .PP Notes: .TP o If you access a variable in \fIexpr\fR that is not in the list of arguments, the "global" value (if any) is used. .TP o Function and parameter names are significant only to 12 characters. .TP o The \fBvalue()\fR function \fIalways\fR accesses the "global" value of a variable, even if it has the same name as an argument. For example: .RS .PP .nf fset func(x) value("x") set x 1 set y func(5) .fi .PP The above sequence sets y to 1, which is the global value of x. .RE .TP o User-defined functions may call other functions, including other user-defined functions. However, recursive calls are not allowed. .TP o User-defined functions are not syntax-checked when they are defined; parsing occurs only when they are called. .TP o If a user-defined function has the same name as a built-in function, it is ignored and the built-in function is used. To prevent conflicts with future versions of \fBRemind\fR (which may define more built-in functions), you may wish to name all user-defined functions beginning with an underscore. .PP .SH PRECISE SCHEDULING .PP The \fBWARN\fR keyword allows precise control over advance warning in a more flexible manner than the \fIdelta\fR mechanism. It should be followed by the name of a user-defined function, \fIwarn_function\fR. .PP If a \fIwarn_function\fR is supplied, then it must take one argument of type \fBINT\fR. \fBRemind\fR ignores any delta, and instead calls \fIwarn_function\fR successively with the arguments 1, 2, 3, ... .PP \fIWarn_function\fR's return value \fIn\fR is interpreted as follows: .TP o If \fIn\fR is positive, then the reminder is triggered exactly \fIn\fR days before its trigger date. .TP o If \fIn\fR is negative, then it is triggered \fIn\fR days before its trigger date, \fInot counting\fR \fBOMIT\fRted days. .PP As an example, suppose you wish to be warned of American Independence Day 5, 3, and 1 days in advance. You could use this: .PP .nf FSET _wfun(x) choose(x, 5, 3, 1, 0) REM 4 July WARN _wfun MSG American Independence Day is %b. .fi .PP .B NOTES .TP 1 If an error occurs during the evaluation of \fIwarn_function\fR, then \fBRemind\fR stops calling it and simply issues the reminder on its trigger date. .TP 2 If the absolute-values of the return values of \fIwarn_function\fR are not monotonically decreasing, \fBRemind\fR stops calling it and issues the reminder on its trigger date. .TP 3 \fIWarn_function\fR should (as a matter of good style) return 0 as the final value in its sequence of return values. However, a reminder will \fIalways\fR be triggered on its trigger date, regardless of what \fIwarn_function\fR does. .PP Similarly to \fBWARN\fR, the \fBSCHED\fR keyword allows precise control over the scheduling of timed reminders. It should be followed by the name of a user-defined function, \fIsched_function\fR. .PP If a scheduling function is supplied, then it must take one argument of type \fBINT\fR. Rather than using the \fBAT\fR time, time \fIdelta\fR, and time \fIrepeat\fR, \fBRemind\fR calls the scheduling function to determine when to trigger the reminder. The first time the reminder is queued, the scheduling function is called with an argument of 1. Each time the reminder is triggered, it is re-scheduled by calling the scheduling function again. On each call, the argument is incremented by one. .PP The return value of the scheduling function must be an \fBINT\fR or a \fBTIME\fR. If the return value is a \fBTIME\fR, then the reminder is re-queued to trigger at that time. If it is a positive integer \fIn\fR, then the reminder is re-queued to trigger at the previous trigger time plus \fIn\fR minutes. Finally, if it is a negative integer or zero, then the reminder is re-queued to trigger \fIn\fR minutes before the \fBAT\fR time. Note that there must be an \fBAT\fR clause for the \fBSCHED\fR clause to do anything. .PP Here's an example: .PP .nf FSET _sfun(x) choose(x, \-60, 30, 15, 10, 3, 1, 1, 1, 1, 0) REM AT 13:00 SCHED _sfun MSG foo .fi .PP The reminder would first be triggered at 13:00-60 minutes, or at 12:00. It would next be triggered 30 minutes later, at 12:30. Then, it would be triggered at 12:45, 12:55, 12:58, 12:59, 13:00, 13:01 and 13:02. .PP .B NOTES .TP 1 If an error occurs during the evaluation of \fIsched_func\fR, then \fBRemind\fR reverts to using the \fBAT\fR time and the \fIdelta\fR and \fIrepeat\fR values, and never calls \fIsched_func\fR again. .TP 2 If processing \fIsched_func\fR yields a time earlier than the current system time, it is repeatedly called with increasing argument until it yields a value greater than or equal to the current time. However, if the sequence of values calculated during the repetition is not strictly increasing, then \fBRemind\fR reverts to the default behaviour and never calls \fIsched_func\fR again. .TP 3 It is quite possible using \fIsched_func\fR to keep triggering a reminder even after the \fBAT\fR-time. However, it is not possible to reschedule a reminder past midnight \- no crossing of date boundaries is allowed. Also, it is quite possible to \fBnot\fR trigger a reminder on the \fBAT\fR time when you use a scheduling function. However, if your scheduling function is terminated (for reasons 1 and 2) before the \fBAT\fR time of the reminder, it \fIwill\fR be triggered at the \fBAT\fR time, because normal processing takes over. .TP 4 Your scheduling functions should (as a matter of good style) return 0 when no more scheduling is required. See the example. .TP 5 All scheduling functions are evaluated \fIafter\fR the entire Remind script has been read in. So whatever function definitions are in effect at the end of the script are used. .PP .SH THE SATISFY CLAUSE .PP The form of \fBREM\fR that uses \fBSATISFY\fR is as follows: .PP \fBREM\fR \fItrigger\fR \fBSATISFY\fR \fIexpr\fR .PP The way this works is as follows: \fBRemind\fR first calculates a trigger date, in the normal fashion. Next, it sets \fBtrigdate()\fR to the calculated trigger date. It then evaluates \fIexpr\fR. If the result is not the null string or zero, processing ends. Otherwise, \fBRemind\fR computes the next trigger date, and re-tests \fIexpr\fR. This iteration continues until \fIexpr\fR evaluates to non-zero or non-null, or until the iteration limit specified with the \fB\-x\fR command-line option is reached. .PP If \fIexpr\fR is not satisfied, then \fBtrigvalid()\fR is set to 0. Otherwise, \fBtrigvalid()\fR is set to 1. In any event, no error message is issued. .PP This is really useful only if \fIexpr\fR involves a call to the \fBtrigdate()\fR function; otherwise, \fIexpr\fR will not change as \fBRemind\fR iterates. .PP An example of the usefulness of \fBSATISFY\fR: Suppose you wish to be warned of every Friday the 13th. Your first attempt may be: .PP .nf # WRONG! REM Fri 13 +2 MSG Friday the 13th is %b. .fi .PP But this won't work. This reminder triggers on the first Friday on or after the 13th of each month. The way to do it is with a more complicated sequence: .PP .nf REM 13 SATISFY wkdaynum(trigdate()) == 5 IF trigvalid() REM [trigdate()] +2 MSG \\ Friday the 13th is %b. ENDIF .fi .PP Let's see how this works. The \fBSATISFY\fR clause iterates through all the 13ths of successive months, until a trigger date is found whose day-of-week is Friday (== 5). If a valid date was found, we use the calculated trigger date to set up the next reminder. .PP We could also have written: .PP .nf REM Fri SATISFY day(trigdate()) == 13 .fi .PP but this would result in more iterations, since "Fridays" occur more often than "13ths of the month." .PP This technique of using one \fBREM\fR command to calculate a trigger date to be used by another command is quite powerful. For example, suppose you wanted to OMIT Labour day, which is the first Monday in September. You could use: .PP .nf # Note: SATISFY 1 is an idiom for "do nothing" REM Mon 1 Sept SATISFY 1 OMIT [trigdate()] .fi .PP \fBCAVEAT:\fR This \fIonly\fR omits the \fInext\fR Labour Day, not all Labour Days in the future. This could cause strange results, as the \fBOMIT\fR context can change depending on the current date. For example, if you use the following command after the above commands: .PP .nf REM Mon AFTER msg hello .fi .PP the result will not be as you expect. Consider producing a calendar for September, 1992. Labour Day was on Monday, 7 September, 1992. However, when \fBRemind\fR gets around to calculating the trigger for Tuesday, 8 September, 1992, the \fBOMIT\fR command will now be omitting Labour Day for 1993, and the "Mon AFTER" command will not be triggered. (But see the description of \fBSCANFROM\fR in the section "Details about Trigger Computation.") .PP It is probably best to stay away from computing \fBOMIT\fR trigger dates unless you keep these pitfalls in mind. .PP For versions of \fBRemind\fR starting from 03.00.07, you can include a \fBMSG\fR, \fBRUN\fR, etc. clause in a \fBSATISFY\fR clause as follows: .PP .nf REM trigger_stuff SATISFY [expr] MSG body .fi .PP Note that for this case only, the \fIexpr\fR after \fBSATISFY\fR \fImust\fR be enclosed in braces. It must come after all the other components of the trigger, and immediately before the \fBMSG\fR, \fBRUN\fR, etc. keyword. If \fIexpr\fR cannot be satisfied, then the reminder is not triggered. .PP Thus, the "Friday the 13th" example can be expressed more compactly as: .PP .nf REM 13 +2 SATISFY [wkdaynum(trigdate()) == 5] \\ MSG Friday the 13th is %b. .fi .PP And you can trigger a reminder on Mondays, Wednesdays and Thursdays occurring on odd-numbered days of the month with the following: .PP .nf REM Mon Wed Thu SATISFY [day(trigdate())%2] \\ MSG Here it is!!! .fi .PP Note that \fBSATISFY\fR and \fBOMITFUNC\fR can often be used to solve the same problem, though in different ways. Sometimes a \fBSATISFY\fR is cleaner and sometimes an \fBOMITFUNC\fR; experiment and use whichever seems clearer. .PP .SH DEBUGGING REMINDER SCRIPTS .PP Although the command-line \fB\-d\fR option is useful for debugging, it is often overkill. For example, if you turn on the \fB\-dx\fR option for a reminder file with many complex expressions, you'll get a huge amount of output. The \fBDEBUG\fR command allows you to control the debugging flags under program control. The format is: .PP \fBDEBUG\fR [+\fIflagson\fR] [\-\fIflagsoff\fR] .PP \fIFlagson\fR and \fIflagsoff\fR consist of strings of the characters "extvlf" that correspond to the debugging options discussed in the command-line options section. If preceded with a "+", the corresponding group of debugging options is switched on. Otherwise, they are switched off. For example, you could use this sequence to debug a complicated expression: .PP .nf DEBUG +x set a very_complex_expression(many_args) DEBUG \-x .fi .PP .B THE DUMPVARS COMMAND .PP The command \fBDUMPVARS\fR displays the values of variables in memory. Its format is: .PP \fBDUMPVARS\fR [\fIvar\fR...] .PP If you supply a space-separated list of variable names, the corresponding variables are displayed. If you do not supply a list of variables, then all variables in memory are displayed. To dump a system variable, put its name in the list of variables to dump. If you put a lone dollar sign in the list of variables to dump, then all system variables will be dumped. .PP .B THE ERRMSG COMMAND .PP The \fBERRMSG\fR command has the following format: .PP \fBERRMSG\fR \fIbody\fR .PP The \fIbody\fR is passed through the substitution filter (with an implicit trigger date of \fBtoday()\fR) and printed to the error output stream. Example: .PP .nf IF !defined("critical_var") ERRMSG You must supply a value for "critical_var" EXIT ENDIF .fi .PP .B THE EXIT COMMAND .PP The above example also shows the use of the \fBEXIT\fR command. This causes an unconditional exit from script processing. Any queued timed reminders are discarded. If you are in calendar mode (described next), then the calendar processing is aborted. .PP If you supply an \fBINT\fR-type expression after the \fBEXIT\fR command, it is returned to the calling program as the exit status. Otherwise, an exit status of 99 is returned. .PP .B THE FLUSH COMMAND .PP This command simply consists of the word \fBFLUSH\fR on a line by itself. The command flushes the standard output and standard error streams used by \fBRemind\fR. This is not terribly useful to most people, but may be useful if you run \fBRemind\fR as a subprocess of another program, and want to use pipes for communication. .PP .SH CALENDAR MODE .PP If you supply the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR command-line option, then \fBRemind\fR runs in "calendar mode." In this mode, \fBRemind\fR interprets the script repeatedly, performing one iteration through the whole file for each day in the calendar. Reminders that trigger are saved in internal buffers, and then inserted into the calendar in the appropriate places. .PP If you also supply the \fB\-a\fR option, then \fBRemind\fR will not include timed reminders in the calendar. .PP The \fB\-p\fR option is used in conjunction with the \fBRem2PS\fR program to produce a calendar in PostScript format. For example, the following command will send PostScript code to standard output: .PP .nf remind \-p .reminders | rem2ps .fi .PP You can print a PostScript calendar by piping this to the \fBlpr\fR command. .PP If you have a reminder script called ".reminders", and you execute this command: .PP .nf remind \-c .reminders jan 1993 .fi .PP then \fBRemind\fR executes the script 31 times, once for each day in January. Each time it executes the script, it increments the value of \fBtoday()\fR. Any reminders whose trigger date matches \fBtoday()\fR are entered into the calendar. .PP \fBMSG\fR and \fBCAL\fR-type reminders, by default, have their entire body inserted into the calendar. \fBRUN\fR-type reminders are not normally inserted into the calendar. However, if you enclose a portion of the body in the %"...%" sequence, only that portion is inserted. For example, consider the following: .PP .nf REM 6 Jan MSG %"Dianne's birthday%" is %b .fi .PP In the normal mode, \fBRemind\fR would print "Dianne's birthday is today" on 6 January. However, in the calendar mode, only the text "Dianne's birthday" is inserted into the box for 6 January. .PP If you explicitly use the %"...%" sequence in a \fBRUN\fR-type reminder, then the text between the delimiters is inserted into the calendar. If you use the sequence %"%" in a \fBMSG\fR or \fBCAL\fR-type reminder, then no calendar entry is produced for that reminder. .PP .B PRESERVING VARIABLES .PP Because \fBRemind\fR iterates through the script for each day in the calendar, slow operations may severely reduce the speed of producing a calendar. .PP For example, suppose you set the variables "me" and "hostname" as follows: .PP .nf SET me shell("whoami") SET hostname shell("hostname") .fi .PP Normally, \fBRemind\fR clears all variables between iterations in calendar mode. However, if certain variables are slow to compute, and will not change between iterations, you can "preserve" their values with the \fBPRESERVE\fR command. Also, since function definitions are preserved between calendar iterations, there is no need to redefine them on each iteration. Thus, you could use the following sequence: .PP .nf IF ! defined("initialized") set initialized 1 set me shell("whoami") set hostname shell("hostname") fset func(x) complex_expr preserve initialized me hostname ENDIF .fi .PP The operation is as follows: On the first iteration through the script, "initialized" is not defined. Thus, the commands between \fBIF\fR and \fBENDIF\fR are executed. The \fBPRESERVE\fR command ensures that the values of initialized, me and hostname are preserved for subsequent iterations. On the next iteration, the commands are skipped, since initialized has remained defined. Thus, time-consuming operations that do not depend on the value of \fBtoday()\fR are done only once. .PP System variables (those whose names start with '$') are automatically preserved between calendar iterations. .PP Note that for efficiency, \fBRemind\fR caches the reminder script (and any \fBINCLUDE\fRd files) in memory when producing a calendar. .PP Timed reminders are sorted and placed into the calendar in time order. These are followed by non-timed reminders. \fBRemind\fR automatically places the time of timed reminders in the calendar according to the \fB\-b\fR command-line option. Reminders in calendar mode are sorted as if the \fB\-g\fR option had been used; you can change the sort order in calendar mode by explicitly using the \fB\-g\fR option to specify a different order from the default. .PP .B REPEATED EXECUTION .PP If you supply a \fIrepeat\fR parameter on the command line, and do not use the \fB\-c\fR, \fB\-p\fR, or \fB\-s\fR options, \fBRemind\fR operates in a similar manner to calendar mode. It repeatedly executes the reminder script, incrementing \fBtoday()\fR with each iteration. The same rules about preserving variables and function definitions apply. Note that using \fIrepeat\fR on the command line also enables the \fB\-q\fR option and disables any \fB\-z\fR option. As an example, if you want to see how \fBRemind\fR will behave for the next week, you can type: .PP .nf remind .reminders '*7' .fi .PP If you want to print the dates of the next 1000 days, use: .PP .nf (echo 'banner %'; echo 'msg [today()]%') | remind - '*1000' .fi .PP .SH INITIALIZING VARIABLES ON THE COMMAND LINE .PP The \fB\-i\fR option is used to initialize variables on the \fBRemind\fR command line. The format is \fB\-i\fR\fIvar\fR\fB=\fR\fIexpr\fR, where \fIexpr\fR is any valid expression. Note that you may have to use quotes or escapes to prevent the shell from interpreting special characters in \fIexpr\fR. You can have as many \fB\-i\fR options as you want on the command line, and they are processed in order. Thus, if a variable is defined in one \fB\-i\fR option, it can be referred to by subsequent \fB\-i\fR options. .PP Note that if you supply a date on the command line, it is not parsed until all options have been processed. Thus, if you use \fBtoday()\fR in any of the \fB\-i\fR expressions, it will return the same value as \fBrealtoday()\fR and not the date supplied on the command line. .PP Any variables defined on the command line are \fBpreserved\fR as with the \fBPRESERVE\fR command. .PP You should not have any spaces between the \fB\-i\fR option and the equal sign; otherwise, strange variable names are created that can only be accessed with the \fBvalue()\fR or \fBdefined()\fR functions. .PP You can also define a function on the command line by using: .PP \fB\-i\fR\fIfunc\fR(\fIargs\fR)=\fIdefinition\fR .PP Be sure to protect special characters from shell interpretation. .SH MORE ABOUT POSTSCRIPT .PP The \fBPS\fR and \fBPSFILE\fR reminders pass PostScript code directly to the printer. They differ in that the \fBPS\fR-type reminder passes its body directly to the PostScript output (after processing by the substitution filter) while the \fBPSFILE\fR-type's body should simply consist of a filename. The \fBRem2PS\fR program will open the file named in the \fBPSFILE\fR-type reminder, and include its contents in the PostScript output. .PP The PostScript-type reminders for a particular day are included in the PostScript output in sorted order of priority. Note that the order of PostScript commands has a \fImajor\fR impact on the appearance of the calendars. For example, PostScript code to shade a calendar box will obliterate code to draw a moon symbol if the moon symbol code is placed in the calendar first. For this reason, you should not provide \fBPS\fR or \fBPSFILE\fR-type reminders with priorities; instead, you should ensure that they appear in the reminder script in the correct order. PostScript code should draw objects working from the background to the foreground, so that foreground objects properly overlay background ones. If you prioritize these reminders and run the script using descending sort order for priorities, the PostScript output will not work. .PP All of the PostScript code for a particular date is enclosed in a \fBsave\fR-\fBrestore\fR pair. However, if several PostScript-type reminders are triggered for a single day, each section of PostScript is not enclosed in a \fBsave\fR-\fBrestore\fR pair - instead, the entire body of included PostScript is enclosed. .PP PostScript-type reminders are executed by the PostScript printer before any regular calendar entries. Thus, regular calendar entries will overlay the PostScript-type reminders, allowing you to create shaded or graphical backgrounds for particular days. .PP Before executing your PostScript code, the origin of the PostScript coordinate system is positioned to the bottom left-hand corner of the "box" in the calendar representing \fBtoday()\fR. This location is exactly in the middle of the intersection of the bottom and left black lines delineating the box - you may have to account for the thickness of these lines when calculating positions. .PP Several PostScript variables are available to the PostScript code you supply. All distance and size variables are in PostScript units (1/72 inch.) The variables are: .TP LineWidth The width of the black grid lines making up the calendar. .TP Border The border between the center of the grid lines and the space used to print calendar entries. This border is normally blank space. .TP BoxWidth and BoxHeight The width and height of the calendar box, from center-to-center of the black gridlines. .TP InBoxHeight The height from the center of the bottom black gridline to the top of the regular calendar entry area. The space from here to the top of the box is used only to draw the day number. .TP /DayFont, /EntryFont, /SmallFont, /TitleFont and /HeadFont The fonts used to draw the day numbers, the calendar entries, the small calendars, the calendar title (month, year) and the day-of-the-week headings, respectively. .TP DaySize, EntrySize, TitleSize and HeadSize The sizes of the above fonts. (The size of the small calendar font is \fInot\fR defined here.) For example, if you wanted to print the Hebrew date next to the regular day number in the calendar, use: .PP .nf REM PS Border BoxHeight Border sub DaySize sub moveto \\ /DayFont findfont DaySize scalefont setfont \\ ([hebday(today())] [hebmon(today())]) show .fi .PP .RS Note how /DayFont and DaySize are used. .RE .PP Note that if you supply PostScript code, it is possible to produce invalid PostScript files. Always test your PostScript thoroughly with a PostScript viewer before sending it to the printer. You should not use any document structuring comments in your PostScript code. .PP .SH DAEMON MODE .PP If you use the \fB\-z\fR command-line option, \fBRemind\fR runs in the "daemon" mode. In this mode, no "normal" reminders are issued. Instead, only timed reminders are collected and queued, and are then issued whenever they reach their trigger time. .PP In addition, \fBRemind\fR wakes up every few minutes to check the modification date on the reminder script (the filename supplied on the command line.) If \fBRemind\fR detects that the script has changed, it re-executes itself in daemon mode, and interprets the changed script. .PP In daemon mode, \fBRemind\fR also re-reads the remind script when it detects that the system date has changed. .PP In daemon mode, \fBRemind\fR acts as if the \fB\-f\fR option had been used, so to run in the daemon mode in the background, use: .PP .nf remind \-z .reminders & .fi .PP If you use \fBsh\fR or \fBbash\fR, you may have to use the "nohup" command to ensure that the daemon is not killed when you log out. .PP .SH PURGE MODE .PP If you supply the \fB\-j\fR command-line option, \fBRemind\fR runs in \fIpurge mode\fR. In this mode, it tries to purge expired reminders from your reminder files. .PP In purge mode, \fBRemind\fR reads your reminder file and creates a new file by appending ".purged" to the original file name. Note that \fBRemind\fR \fInever\fR edits your original file; it always creates a new .purged file. .PP If you invoke \fBRemind\fR against a directory instead of a file, then a .purged file is created for each *.rem file in the directory. .PP Normally, \fBRemind\fR does not create .purged files for INCLUDed files. However, if you supply a numeric argument after \fB\-j\fR, then \fBRemind\fR will create .purged files for the specified level of INCLUDE. For example, if you invoke \fBRemind\fR with the argument \fB\-j2\fR, then .purged files will be created for the file (or directory) specified on the command line, any files included by them, and any files included by those files. However, .purged files will not be created for third-or-higher level INCLUDE files. .PP Determining which reminders have expired is extremely tricky. \fBRemind\fR does its best, but you should always compare the .purged file to the original file and hand-merge the changes back in. .PP Remind annotates the .purged file as follows: .PP An expired reminder is prefixed with: #!P: Expired: .PP In situations where \fBRemind\fR cannot reliably determine that something was expired, you may see the following comments inserted before the problematic line: .PP .nf #!P: Cannot purge SATISFY-type reminders #!P: The next IF evaluated false... #!P: REM statements in IF block not checked for purging. #!P: The previous IF evaluated true. #!P: REM statements in ELSE block not checked for purging #!P: The next IFTRIG did not trigger. #!P: REM statements in IFTRIG block not checked for purging. #!P: Next line has expired, but contains expression... please verify #!P: Next line may have expired, but contains non-constant expression #!P! Could not parse next line: Some-Error-Message-Here .fi .PP \fBRemind\fR always annotates .purged files with lines beginning with "#!P". If such lines are encountered in the \fIoriginal\fR file, they are not copied to the .purged file. .PP .SH SORTING REMINDERS .PP The \fB\-g\fR option causes \fBRemind\fR to sort reminders by trigger date, time and priority before issuing them. Note that reminders are still calculated in the order encountered in the script. However, rather than being issued immediately, they are saved in an internal buffer. When \fBRemind\fR has finished processing the script, it issues the saved reminders in sorted order. The \fB\-g\fR option can be followed by up to four characters that must all be "a" or "d". The first character specifies the sort order by trigger date (ascending or descending), the second specifies the sort order by trigger time and the third specifies the sort order by priority. If the fourth character is "d", the untimed reminders are sorted before timed reminders. The default is to sort all fields in ascending order and to sort untimed reminders after timed reminders. .PP In ascending order, reminders are issued with the most imminent first. Descending order is the reverse. Reminders are always sorted by trigger date, and reminders with the same trigger date are then sorted by trigger time. If two reminders have the same date and time, then the priority is used to break ties. Reminders with the same date, time and priority are issued in the order they were encountered. .PP You can define a user-defined function called SORTBANNER that takes one \fBDATE\fR-type argument. In sort mode, the following sequence happens: .PP If \fBRemind\fR notices that the next reminder to issue has a different trigger date from the previous one (or if it is the first one to be issued), then SORTBANNER is called with the trigger date as its argument. The result is coerced to a string, and passed through the substitution filter with the appropriate trigger date. The result is then displayed. .PP Here's an example - consider the following fragment: .PP .nf # Switch off the normal banner BANNER % REM 11 March 1993 ++1 MSG Not so important REM 17 March 1993 ++7 MSG Way in the future REM 10 March 1993 MSG Important Reminder REM 11 March 1993 ++1 MSG Not so important - B FSET sortbanner(x) iif(x == today(), \\ "***** THINGS TO DO TODAY *****", \\ "----- Things to do %b -----") .fi .PP Running this with the \fB-gaa\fR option on 10 March 1993 produces the following output: .PP .nf ***** THINGS TO DO TODAY ***** Important Reminder ----- Things to do tomorrow ----- Not so important Not so important - B ----- Things to do in 7 days' time ----- Way in the future .fi .PP You can use the \fBargs()\fR built-in function to determine whether or not SORTBANNER has been defined. (This could be used, for example, to provide a default definition for SORTBANNER in a system-wide file included at the end of the user's file.) Here's an example: .PP .nf # Create a default sortbanner function if it hasn't already # been defined if args("sortbanner") != 1 fset sortbanner(x) "--- Things to do %b ---" endif .fi .PP .SH MSGPREFIX() AND MSGSUFFIX() .PP You can define two functions in your script called \fBmsgprefix()\fR and \fBmsgsuffix()\fR. They should each accept one argument, a number from 0 to 9999. .PP In normal mode, for \fBMSG\fR- and \fBMSF\fR-type reminders, the following sequence occurs when \fBRemind\fR triggers a reminder: .TP o If \fBmsgprefix()\fR is defined, it is evaluated with the priority of the reminder as its argument. The result is printed. It is \fInot\fR passed through the substitution filter. .TP o The body of the reminder is printed. .TP o If \fBmsgsuffix()\fR is defined, it is evaluated with the priority of the reminder as its argument. The result is printed. It is \fInot\fR passed through the substitution filter. .PP Here's an example: The following definition causes priority-0 reminders to be preceded by "URGENT", and priority-6000 reminders to be preceded by "(not important)". .PP .nf fset msgprefix(x) iif(x==0, "URGENT: ", \\ x==6000, "(not important) ", "") .fi .PP In Calendar Mode (with the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR options), an analogous pair of functions named \fBcalprefix()\fR and \fBcalsuffix()\fR can be defined. They work with all reminders that produce an entry in the calendar (i.e., \fBCAL\fR- and possibly \fBRUN\fR-type reminders as well as \fBMSG\fR-type reminders.) .PP .B NOTES .PP Normally, the body of a reminder is followed by a carriage return. Thus, the results of \fBmsgsuffix()\fR will appear on the next line. If you don't want this, end the body of the reminder with a percentage sign, "%". If you want a space between your reminders, simply include a carriage return (\fBchar(13)\fR) as part of the \fBmsgsuffix()\fR return value. .PP If \fBRemind\fR has problems evaluating \fBmsgprefix()\fR, \fBmsgsuffix()\fR or \fBsortbanner()\fR, you will see a lot of error messages. For an example of this, define the following: .PP .nf fset msgprefix(x) x/0 .fi .PP .SH FOREIGN LANGUAGE SUPPORT .PP Your version of \fBRemind\fR may have been compiled to support a language other than English. This support may or may not be complete - for example, all error and usage messages may still be in English. However, at a minimum, foreign-language versions of \fBRemind\fR will output names of months and weekdays in the foreign language. Also, the substitution mechanism will substitute constructs suitable for the foreign language rather than for English. .PP A foreign-language version of \fBRemind\fR will accept either the English or foreign-language names of weekdays and months in a reminder script. However, for compatibility between versions of \fBRemind\fR, you should use only the English names in your scripts. Also, if your C compiler or run-time libraries are not "8-bit clean" or don't understand the ISO-Latin character set, month or day names with accented letters may not be recognized. .PP .SH THE HEBREW CALENDAR .PP \fBRemind\fR has support for the Hebrew calendar, which is a luni-solar calendar. This allows you to create reminders for Jewish holidays, jahrzeits (anniversaries of deaths) and smachot (joyous occasions.) .PP .B THE HEBREW YEAR .PP The Hebrew year has 12 months, alternately 30 and 29 days long. The months are: Tishrey, Heshvan, Kislev, Tevet, Shvat, Adar, Nisan, Iyar, Sivan, Tamuz, Av and Elul. In Biblical times, the year started in Nisan, but Rosh Hashana (Jewish New Year) is now celebrated on the 1st and 2nd of Tishrey. .PP In a cycle of 19 years, there are 7 leap years, being years 3, 6, 8, 11, 14, 17 and 19 of the cycle. In a leap year, an extra month of 30 days is added before Adar. The two Adars are called Adar A and Adar B. .PP For certain religious reasons, the year cannot start on a Sunday, Wednesday or Friday. To adjust for this, a day is taken off Kislev or added to Heshvan. Thus, a regular year can have from 353 to 355 days, and a leap year from 383 to 385. .PP When Kislev or Heshvan is short, it is called \fIchaser\fR, or lacking. When it is long, it is called \fIshalem\fR, or full. .PP The Jewish date changes at sunset. However, \fBRemind\fR will change the date at midnight, not sunset. So in the period between sunset and midnight, Remind will be a day earlier than the true Jewish date. This should not be much of a problem in practice. .PP The computations for the Jewish calendar were based on the program "hdate" written by Amos Shapir of the Hebrew University of Jerusalem, Israel. He also supplied the preceding explanation of the calendar. .PP .B HEBREW DATE FUNCTIONS .TP .B hebday(d_date) Returns the day of the Hebrew month corresponding to the \fIdate\fR parameter. For example, 12 April 1993 corresponds to 21 Nisan 5753. Thus, hebday('1993/04/12') returns 21. .TP .B hebmon(d_date) Returns the name of the Hebrew month corresponding to \fIdate\fR. For example, hebmon('1993/04/12') returns "Nisan". .TP .B hebyear(d_date) Returns the Hebrew year corresponding to \fIdate\fR. For example, hebyear('1993/04/12') returns 5753. .TP .B hebdate(i_day, s_hebmon [,id_yrstart [,i_jahr [,i_aflag]]]) The \fBhebdate()\fR function is the most complex of the Hebrew support functions. It can take from 2 to 5 arguments. It returns a \fBDATE\fR corresponding to the Hebrew date. .PP .RS The \fIday\fR parameter can range from 1 to 30, and specifies the day of the Hebrew month. The \fIhebmon\fR parameter is a string that must name one of the Hebrew months specified above. Note that the month must be spelled out in full, and use the English transliteration shown previously. You can also specify "Adar A" and "Adar B." Month names are not case-sensitive. .PP The \fIyrstart\fR parameter can either be a \fBDATE\fR or an \fBINT\fR. If it is a \fBDATE\fR, then the \fBhebdate()\fR scans for the first Hebrew date on or after that date. For example: .PP .nf hebdate(15, "Nisan", '1990/01/01') .fi .PP returns 1990/03/30, because that is the first occurrence of 15 Nisan on or after 1 January 1990. .PP If \fIyrstart\fR is an \fBINT\fR, it is interpreted as a Hebrew year. Thus: .PP .nf hebdate(22, "Kislev", 5756) .fi .PP returns 1995/12/15, because that date corresponds to 22 Kislev, 5756. Note that none of the Hebrew date functions will work with dates outside \fBRemind's\fR normal range for dates. .PP If \fIyrstart\fR is not supplied, it defaults to \fBtoday()\fR. .PP The \fIjahr\fR modifies the behaviour of \fBhebdate()\fR as follows: .PP If \fIjahr\fR is 0 (the default), then \fBhebdate()\fR keeps scanning until it finds a date that exactly satisfies the other parameters. For example: .PP .nf hebdate(30, "Adar A", 1993/01/01) .fi .PP returns 1995/03/02, corresponding to 30 Adar A, 5755, because that is the next occurrence of 30 Adar A after 1 January, 1993. This behaviour is appropriate for Purim Katan, which only appears in leap years. .PP If \fIjahr\fR is 1, then the date is modified as follows: .TP o 30 Heshvan is converted to 1 Kislev in years when Heshvan is \fIchaser\fR .TP o 30 Kislev is converted to 1 Tevet in years when Kislev is \fIchaser\fR .TP o 30 Adar A is converted to 1 Nisan in non-leapyears .TP o Other dates in Adar A are moved to the corresponding day in Adar in non-leapyears .PP This behaviour is appropriate for smachot (joyous occasions) and for some jahrzeits - see "JAHRZEITS." .PP if \fIjahr\fR is 2, then the date is modified as follows: .TP o 30 Kislev and 30 Heshvan are converted to 29 Kislev and 29 Heshvan, respectively, if the month is \fIchaser\fR .TP o 30 Adar A is converted to 30 Shvat in non-leapyears .TP o Other dates in Adar A are moved to the corresponding day in Adar in non-leapyears .PP if \fIjahr\fR is not 0, 1, or 2, it is interpreted as a Hebrew year, and the behaviour is calculated as described in the next section, "JAHRZEITS." .PP The \fIaflag\fR parameter modifies the behaviour of the function for dates in Adar during leap years. The \fIaflag\fR is \fIonly\fR used if \fIyrstart\fR is a \fBDATE\fR type. .PP The \fIaflag\fR only affects date calculations if \fIhebmon\fR is specified as "Adar". In leap years, the following algorithm is followed: .TP o If \fIaflag\fR is 0, then the date is triggered in Adar B. This is the default. .TP o If \fIaflag\fR is 1, then the date is triggered in Adar A. This may be appropriate for jahrzeits in the Ashkenazi tradition; consult a rabbi. .TP o If \fIaflag\fR is 2, then the date is triggered in both Adar A and Adar B of a leap year. Some Ashkenazim perform jahrzeit in both Adar A and Adar B. .RE .PP .B JAHRZEITS .PP A jahrzeit is a yearly commemoration of someone's death. It normally takes place on the anniversary of the death, but may be delayed if burial is delayed - consult a rabbi for more information. .PP In addition, because some months change length, it is not obvious which day the anniversary of a death is. The following rules are used: .TP o If the death occurred on 30 Heshvan, and Heshvan in the year after the death is \fIchaser\fR, then the jahrzeit is observed on 29 Heshvan in years when Heshvan is \fIchaser\fR. Otherwise, the yahrzeit is observed on 1 Kislev when Heshvan is \fIchaser\fR. .TP o If the death occurred on 30 Kislev, and Kislev in the year after the death is \fIchaser\fR, then the jahrzeit is observed on 29 Kislev in years when Kislev is \fIchaser\fR. Otherwise, the yahrzeit is observed on 1 Tevet when Kislev is \fIchaser\fR. .TP o If the death occurred on 1-29 Adar A, it is observed on 1-29 Adar in non-leapyears. .TP o If the death occurred on 30 Adar A, it is observed on 30 Shvat in a non-leapyear. .PP Specifying a Hebrew year for the \fIjahr\fR parameter causes the correct behaviour to be selected for a death in that year. You may also have to specify \fIaflag\fR, depending on your tradition. .PP The jahrzeit information was supplied by Frank Yellin, who quoted "The Comprehensive Hebrew Calendar" by Arthur Spier, and "Calendrical Calculations" by E. M. Reingold and Nachum Dershowitz. .PP .SH OUT-OF-BAND REMINDERS .PP The \fBSPECIAL\fR keyword is used to transmit "out-of-band" information to \fBRemind\fR backends, such as \fBtkremind\fR or \fBRem2PS\fR. They are used only when piping data from a \fBremind \-p\fR line. (Note that the COLOR special is an exception; it downgrades to the equivalent of MSG in \fBremind's\fR normal mode of operation.) .PP The various \fBSPECIAL\fRs recognized are particular for each backend; however, there are three \fBSPECIAL\fRs that all backends should attempt to support. They are currently supported by \fBRem2PS\fR, \fBtkremind\fR and \fBrem2html\fR. .PP The \fBSHADE\fR special replaces the \fBpsshade()\fR function. Use it like this: .nf REM Sat Sun SPECIAL SHADE 128 REM Mon SPECIAL SHADE 255 0 0 .fi The \fBSHADE\fR keyword is followed by either one or three numbers, from 0 to 255. If one number is supplied, it is interpreted as a grey-scale value from black (0) to white (255). If three numbers are supplied, they are interpreted as RGB components from minimum (0) to maximum (255). The example above shades weekends a fairly dark grey and makes Mondays a fully-saturated red. (These shadings appear in calendars produced by \fBRem2PS\fR, \fBtkremind\fR and \fBrem2html\fR.) .PP The \fBMOON\fR special replaces the \fBpsmoon()\fR function. Use it like this: .nf REM [moondate(0)] SPECIAL MOON 0 REM [moondate(1)] SPECIAL MOON 1 REM [moondate(2)] SPECIAL MOON 2 REM [moondate(3)] SPECIAL MOON 3 .fi These draw little moons on the various calendars. The complete syntax of the \fBMOON\fR special is as follows: .nf ... SPECIAL MOON phase moonsize fontsize msg .fi .PP \fIPhase\fR is a number from 0 to 3, with 0 representing a new moon, 1 the first quarter, 2 a full moon and 3 the last quarter. .PP \fImoonsize\fR is the diameter in PostScript units of the moon to draw. If omitted or supplied as \-1, the backend chooses an appropriate size. .PP \fIfontsize\fR is the font size in PostScript units of the \fImsg\fR .PP \fIMsg\fR is additional text that is placed near the moon glyph. .PP Note that only the \fBRem2PS\fR backend supports \fImoonsize\fR and \fIfontsize\fR; the other backends use fixed sizes. .PP The \fBCOLOR\fR special lets you place colored reminders in the calendar. Use it like this: .nf REM ... SPECIAL COLOR 255 0 0 This is a bright red reminder REM ... SPECIAL COLOR 0 128 0 This is a dark green reminder .fi You can spell COLOR either the American way ("COLOR") or the British way ("COLOUR"). This manual will use the American way. Immediately following COLOR should be three decimal numbers ranging from 0 to 255 specifying red, green and blue intensities, respectively. The rest of the line is the text to put in the calendar. .PP The COLOR special is "doubly special", because in its normal operating mode, \fBremind\fR treats a COLOR special just like a MSG-type reminder. Also, if you invoke \fBRemind\fR with \fB\-cc\fR..., then it approximates SPECIAL COLOR reminders on your terminal. .PP The \fBWEEK\fR special lets you place annotations such as the week number in the calendar. For example, this would number each Monday with the ISO 8601 week number. The week number is shown like this: "(W\fIn\fR)" in this example, but you can put whatever text you like after the WEEK keyword. .nf REM Monday SPECIAL WEEK (W[weekno()]) .fi .SH MISCELLANEOUS .PP .B COMMAND ABBREVIATIONS .PP The following tokens can be abbreviated: .TP o \fBREM\fR can be omitted - it is implied if no other valid command is present. .TP o \fBCLEAR-OMIT-CONTEXT\fR --> \fBCLEAR\fR .TP o \fBPUSH-OMIT-CONTEXT\fR --> \fBPUSH\fR .TP o \fBPOP-OMIT-CONTEXT\fR --> \fBPOP\fR .TP o \fBDUMPVARS\fR --> \fBDUMP\fR .TP o \fBBANNER\fR --> \fBBAN\fR .TP o \fBINCLUDE\fR --> \fBINC\fR .TP o \fBSCANFROM\fR --> \fBSCAN\fR .PP .B NIFTY EXAMPLES .PP This section is a sampling of what you can do with \fBRemind\fR. .PP .nf REM 5 Feb 1991 AT 14:00 +45 *30 \\ RUN mail \-s "Meeting at %2" $LOGNAME wrote \fBRemind\fR. The moon code was copied largely unmodified from "moontool" by John Walker. The sunrise and sunset functions use ideas from programs by Michael Schwartz and Marc T. Kaufman. The Hebrew calendar support was taken from "hdate" by Amos Shapir. OS/2 support was done by Darrel Hankerson, Russ Herman, and Norman Walsh. The supported foreign languages and their translators are listed below. Languages marked "complete" support error messages and usage instructions in that language; all others only support the substitution filter mechanism and month/day names. .PP \fBGerman\fR -- Wolfgang Thronicke .PP \fBDutch\fR -- Willem Kasdorp and Erik-Jan Vens .PP \fBFinnish\fR -- Mikko Silvonen (complete) .PP \fBFrench\fR -- Laurent Duperval (complete) .PP \fBNorwegian\fR -- Trygve Randen .PP \fBDanish\fR -- Mogens Lynnerup .PP \fBPolish\fR -- Jerzy Sobczyk (complete) .PP \fBBrazilian Portuguese\fR -- Marco Paganini (complete) .PP \fBItalian\fR -- Valerio Aimale .PP \fBRomanian\fR -- Liviu Daia .PP \fBSpanish\fR -- Rafa Couto .PP \fBIcelandic\fR -- Bj\(:orn Dav\('i\[Sd]sson .SH BUGS .PP There's no good reason why read-only system variables are not implemented as functions, or why functions like \fBversion()\fR, etc. are not implemented as read-only system variables. .PP Hebrew dates in \fBRemind\fR change at midnight instead of sunset. .PP Language should be selectable at run-time, not compile-time. Don't expect this to happen soon! .PP \fBRemind\fR has some built-in limits (for example, number of global \fBOMIT\fRs.) .PP .SH BIBLIOGRAPHY .PP Nachum Dershowitz and Edward M. Reingold, "Calendrical Calculations", \fISoftware\-Practice and Experience\fR, Vol. 20(9), Sept. 1990, pp 899-928. .PP L. E. Doggett, \fIAlmanac for computers for the year 1978\fR, Nautical Almanac Office, USNO. .PP Richard Siegel and Michael and Sharon Strassfeld, \fIThe First Jewish Catalog\fR, Jewish Publication Society of America. .PP .SH SEE ALSO .PP rem, rem2ps, tkremind remind-03.01.15/man/tkremind.10000644000076400007640000003324212514120337014015 0ustar dfsdfs.TH TKREMIND 1 "15 February 1998" .UC 4 .SH NAME tkremind \- graphical front-end to Remind calendar program .SH SYNOPSIS .B tkremind \fR[\fIoptions\fR] [\fIread_file\fR] [\fIwrite_file\fR] .SH DESCRIPTION \fBTkRemind\fR is a graphical front-end to the \fBRemind\fR program. It provides a friendly graphical interface which allows you to view your calendar and add reminders without learning the syntax of \fBRemind\fR. Although not all of \fBRemind\fR's features are available with \fBTkRemind\fR, \fBTkRemind\fR gives you an opportunity to edit the reminder commands which it creates. This allows you to learn \fBRemind\fR's syntax and then add extra features as you become a more sophisticated \fBRemind\fR programmer. \fBTkRemind\fR is written in Tcl, and requires version 8.0 (or higher). It also requires a \fBwish\fR binary. .SH OPTIONS \fBTkRemind\fR itself has no options. However, it passes certain options on to \fBRemind\fR. The options it passes are \fB\-b\fR, \fB\-g\fR, \fB\-x\fR, \fB\-i\fR and \fB\-m\fR. See the \fBRemind\fR man page for details about the options. Note that \fBTkRemind\fR will respect the \fB\-m\fR and \fB\-b1\fR options and adjust its appearance accordingly. \fIRead_file\fR is the file from which \fBTkRemind\fR reads reminders. It is in standard \fBRemind\fR format. \fIWrite_file\fR is the file to which \fBTkRemind\fR writes reminders which you add using the GUI. If \fIRead_file\fR is omitted, it defaults to \fB$HOME/.reminders\fR. If \fIWrite_file\fR is omitted, it defaults to \fIRead_file\fR. You may wish to have a different \fIWrite_file\fR from \fIRead_file\fR if you want to collect all of \fBTkRemind\fR's reminders in one place. Suppose your main file is \fI$HOME/.reminders\fR and you want \fBTkRemind\fR to put its reminders in \fI$HOME/.tkreminders\fR. In \fI$HOME/.reminders\fR, include the line: .PP .nf INCLUDE [getenv("HOME")]/.tkreminders .fi .PP .SH THE CALENDAR WINDOW When you start \fBTkRemind\fR, it displays a calendar for the current month, with today's date highlighted. Reminders are filled into each box on the calendar. If a box contains many reminders, you can scroll it up and down by dragging mouse button 2 in the box. Note that there is no specific indication of an over-full box; you'll just have to notice that the box appears completely full. .SH NAVIGATING To change to the previous or next month, click the \fB<\-\fR or \fB\->\fR button, respectively. To change back to the current month, click \fBToday\fR. To go to a specific month, click \fBGo To Date...\fR. This pops up a dialog box which allows you to select a month and enter a year. Once you've done this, click \fBGo\fR to go to the date, or \fBCancel\fR to cancel. To exit \fBTkRemind\fR, click \fBQuit\fR. .SH ADDING REMINDERS To add a reminder, click button 1 in any day number in the calendar. The \fBAdd Reminder...\fR dialog will pop up, with values preselected for the day you clicked. The dialog has six basic groups of controls. The first three lines select one of three types of reminders. Choose the type of reminder with the radio buttons, and choose the values of the days, months, and years by selecting values from pull-down menus. The pull-down menus appear when you click the raised value buttons. The next control specifies an expiry date for the reminder. Select the check button to enable an expiry date, and fill in the values using pull-down menus. The third control specifies how much advance notice you want (if any), and whether or not weekends and holidays are counted when computing advance notice. The fourth control specifies which days \fBRemind\fR considers as part of the weekend. This can affect the interpretation of "weekday" in the second and third types of reminders. The fifth control associates a time with the reminder. You can also specify advance notice, possibly repeating. The sixth control specifies what \fBRemind\fR should do if a reminder falls on a holiday or weekend. Enter the body of the reminder into the \fBBody:\fR text entry. To add the reminder to the reminder file, click \fBAdd to reminder file\fR. To close the dialog without adding the reminder to the file, click \fBCancel\fR. To preview the reminder, click \fBPreview reminder\fR. This pops up the \fBPreview reminder\fR dialog box. .SH PREVIEWING REMINDERS The \fBPreview reminder\fR dialog box is an excellent way to learn \fBRemind\fR. It displays the \fBRemind\fR command which realizes the reminder you entered using the \fBAdd Reminder...\fR dialog. You can edit the reminder, thereby gaining access to advanced features of \fBRemind\fR. You can also use it simply to play around and discover \fBRemind\fR's idioms for expressing different types of reminders. .SH PRINTING To print the current month's calender, click \fBPrint...\fR on the main calendar window. This brings up the print dialog. Printing either produces a PostScript file or sends PostScript to a UNIX command. Select the print destination by choosing either \fBTo file:\fR or \fBTo command:\fR in the print dialog. Press \fBBrowse...\fR to bring up a file browser. In the file browser, you can enter a filename in the text entry, double-click on a filename in the listbox, or double-click on a directory to navigate the file system. You can also type the first few characters of a file name in the text entry box and press space to complete the name to the first matching entry. The \fBMatch:\fR box contains a filename wildcard which filters files in the listbox. You can change the filter and press enter to rescan the directory. Select the appropriate paper size and orientation. Activate \fBFill page\fR if you want the calendar to fill the page. This should be the normal case unless you have many reminders in a particular day. (See the \fBRem2PS\fR documentation.) Finally, click \fBPrint\fR to print or \fBCancel\fR to cancel. Note that during printing, \fBRemind\fR is \fInot\fR called with the \fB-itkremind=1\fR option, because it is operated in normal PostScript-producing mode. .SH EDITING REMINDERS If you created a reminder with \fBTkRemind\fR, it will turn red as the mouse cursor passes over it in the calendar window. Click button-1 over the reminder and you will be presented with a dialog window whose state is identical to the one used to create the reminder. At this point, you can change the reminder by editing the dialog entries and selecting \fBReplace reminder\fR. You can delete the reminder entirely by selecting \fBDelete reminder\fR. The remaining buttons, \fBPreview reminder\fR and \fBCancel\fR operate identically to the dialog in "ADDING REMINDERS." Note that if you edit a reminder (using \fBPreview reminder\fR), any edits you made are \fInot\fR retained in the dialog box. You should not attempt to edit such reminders; you have to retype them in the \fBPreview reminder\fR dialog. If the reminder was not created with \fBTkRemind\fR, you can't edit it with \fBTkRemind\fR. .SH USING A TEXT EDITOR If you have set the "text editor" option correctly, right-clicking on a reminder will bring up a text editor on the file containing the reminder. The cursor will be positioned on the line that generated the reminder. .SH BACKGROUND REMINDERS If you create "timed" reminders, \fBTkRemind\fR will queue them in the background and pop up boxes as they are triggered. Additionally, if you created the reminder using \fBTkRemind\fR, you will be given the option of "turning off" the reminder for the rest of the day. \fBTkRemind\fR achieves queueing of background reminders by running \fBRemind\fR in \fIserver mode\fR, described later. .SH OPTIONS The final button on the calendar window, \fBOptions\fR, lets you configure certain aspects of \fBTkRemind\fR. The configuration options are: .TP .B Start up Iconified If this is selected, \fBTkRemind\fR starts up iconified. Otherwise, it starts up in a normal window. .TP .B Show Today's Reminders on Startup If this is selected, \fBTkRemind\fR shows a text window containing reminders which would be issued by "remind \-q \-a \-r" on startup, and when the date changes at midnight. .TP .B Confirm Quit If this is selected, you will be asked to confirm when you press \fBQuit\fR. If not, \fBTkRemind\fR quits without prompting. .TP .B Automatically close pop-up reminders after a minute If this is selected, pop-up reminder boxes will be closed after one minute has elapsed. Otherwise, they remain on your screen forever until you explicitly dismiss them. .TP .B Beep terminal when popping up a reminder If selected, \fBTkRemind\fR beeps the terminal bell when a queued reminder pops up. .TP .B Deiconify calendar window when popping up a reminder If selected, does what it says. .TP .B Run command when popping up a reminder If this entry is not blank, the specified command is run whenever a background reminder pops up. .TP .B Feed popped-up reminder to command's standard input If selected, feeds the text of the reminder to the command described above. .TP .B E-mail reminders here if popup not dismissed If you enter a non-blank e-mail address in this field, then \fBTkRemind\fR will e-mail you a reminder if you don't dismiss the popup box within one minute. This is useful if you need to leave your terminal but want your reminders to "follow" you via e-mail. .TP .B Name or IP address of SMTP server \fBTkRemind\fR uses a direct SMTP connection to send mail. Enter the IP address of your SMTP server here. .TP .B Text Editor This specifies a text editor to invoke when a reminder is right-clicked. The characters "%d" are replaced with the lined number of the file containing the reminder, and "%s" are replaced with the file name. Useful strings might be "emacs +%d %s" or "gvim +%d %s" .PP Once you've configured the options the way you like them, press \fBApply Options\fR to put them into effect, \fBSave Options\fR to put them into effect and save them in $HOME/.tkremindrc, or \fBCancel\fR to cancel any changes you made. .SH KEYBOARD SHORTCUTS \fBTkRemind\fR's main window includes the following keyboard shortcuts: .TP .B Ctrl-Q Quit .TP .B Left Arrow Previous Month .TP .B Right Arrow Next Month .TP .B Home Today .SH ODDS AND ENDS \fBTkRemind\fR performs some basic consistency checks when you add or preview a reminder. However, if you edit a reminder in the previewer, \fBTkRemind\fR does \fInot\fR check the edited reminder. You can produce illegal reminders which may cause problems. (This is one good reason to isolate \fBTkRemind\fR's reminders in a separate file.) .PP \fBTkRemind\fR does \fInot\fR check the body of the reminder in any way. You can use the normal \fBRemind\fR substitution sequences in the body. Furthermore, if you use expression-pasting in the body, \fBTkRemind\fR does \fInot\fR validate the expressions. .PP When \fBTkRemind\fR invokes \fBRemind\fR, it supplies the option: .PP .nf \-itkremind=1 .fi .PP on the command line. So, in your \fBRemind\fR file, you can include: .PP .nf IF defined("tkremind") # Then I'm probably being invoked by TkRemind ENDIF .fi .PP You can use this to activate certain reminders in different ways for \fBTkRemind\fR (for example). .PP \fBTkRemind\fR uses tags to keep track of reminders in the script file. It also places special comments in the reminder file to store additional state. You can certainly mix "hand-crafted" reminders with reminders created by \fBTkRemind\fR if you are aware of the following rules and limitations: .TP o \fBTkRemind\fR uses \fBTAG\fRs of the form \fBTKTAG\fR\fInnn\fR where \fInnn\fR is a number. You should not use such \fBTAG\fRs in hand-crafted reminders. .TP o Do not edit lines starting with "# TKTAGnnn", "# TKEND", or any lines in between. You can move such lines, but be careful to move them as a single block. .TP o Hand-crafted reminders cannot be edited with \fBTkRemind\fR, and for hand-crafted timed reminders, you will not be presented with the "Don't remind me again" option when they pop up. .SH SERVER MODE \fBRemind\fR has a special mode for interacting with programs like \fBTkRemind\fR. This mode is called \fIserver mode\fR and is selected by supplying the \fB\-z0\fR option to \fBRemind\fR. In server mode, \fBRemind\fR operates similar to daemon mode, except it reads commands (one per line) from standard input and writes status lines to standard output. The commands accepted in server mode are: .TP EXIT Terminate the \fBRemind\fR process. EOF on standard input does the same thing. .TP STATUS Return the number of queued reminders. .TP REREAD Re-read the reminder file .PP The status lines written are as follows: .TP NOTE reminder \fItime\fR \fItag\fR Signifies the beginning of a timed reminder whose trigger time is \fItime\fR with tag \fItag\fR. If the reminder has no tag, an asterisk is supplied for \fItag\fR. All lines following this line are the body of the reminder, until the line \fBNOTE endreminder\fR is transmitted. .TP NOTE newdate This line is emitted whenever \fBRemind\fR has detected a rollover of the system date. The front-end program should redraw its calendar or take whatever other action is needed. .TP NOTE reread This line is emitted whenever the number of reminders in \fBRemind\fR's queue changes because of a date rollover or a \fBREREAD\fR command. The front-end should issue a \fBSTATUS\fR command in response to this message. .TP NOTE queued \fIn\fR This line is emitted in response to a \fBSTATUS\fR command. The number \fIn\fR is the number of reminders in the queue. .SH AUTHOR TkRemind is now supported by Roaring Penguin Software Inc. (http://www.roaringpenguin.com) .PP TkRemind was written by Dianne Skoll . \fBTkRemind\fR is Copyright 1996-1998 by Dianne Skoll, Copyright 1999 by Roaring Penguin Software Inc. .SH FILES $HOME/.reminders -- default reminder file. $HOME/.tkremindrc -- \fBTkRemind\fR saved options. .SH SEE ALSO remind, rem2ps remind-03.01.15/scripts/README0000644000076400007640000000024011057403122013677 0ustar dfsdfsFiles in this directory: tkremind -- Tcl/Tk graphical calendar using Remind as engine cm2rem.tcl -- Convert Sun's "cm" calendar manager files to Remind. remind-03.01.15/scripts/cm2rem.tcl0000644000076400007640000002412012514120337014716 0ustar dfsdfs#!/bin/sh # -*-Mode: TCL;-*- #-------------------------------------------------------------- # cm2rem.tcl # # A cheesy Tcl script to convert Sun's "cm" calendar manager # files (version 3 only) to Remind format. # # This file is part of REMIND. # Copyright (C) 1992-1998 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. # #-------------------------------------------------------------- # the next line restarts using tclsh \ exec tclsh "$0" "$@" set i 0 foreach month {January February March April May June July August September October November December} { incr i set MonthNum($month) $i set FullMonth([string range $month 0 2]) $month } #*********************************************************************** # %PROCEDURE: convertParens # %ARGUMENTS: # line -- a line read from a cm file # %RETURNS: # A new line with all ( and ) outside quotes converted to { and }. # This cheap trick allows us to use Tcl's built-in list manipulation # functions to munge the line. #*********************************************************************** proc convertParens { line } { # Convert all ( and ) to { and } unless they are inside a quoted # string set out "" set len [string length $line] set inQuotes 0 for {set i 0} {$i < $len} {incr i} { set char [string range $line $i $i] if {$char == "\\" && $inQuotes} { append out $char incr i set char [string range $line $i $i] append out $char continue } if {$char == "(" && !$inQuotes} { set char \{ } if {$char == ")" && !$inQuotes} { set char \} } if {$char == "\""} { set inQuotes [expr !$inQuotes] } append out $char } return $out } #*********************************************************************** # %PROCEDURE: processLine # %ARGUMENTS: # line -- a line read from a cm file # %RETURNS: # Nothing # %DESCRIPTION: # Processes a single line from the file, possibly writing a reminder # in Remind format to stdout #*********************************************************************** proc processLine { line } { global Attributes global FullMonth catch {unset Attributes} # Only convert lines which start with "(add" if {[string range $line 0 3] != "(add"} { return } set line [convertParens $line] # Convert it to a list. CAREFUL: Potential security problem if # $line contains something nasty. eval set line $line set Attributes(body) "" foreach {key val} $line { switch -exact -- $key { "add" { set Attributes(date) $val } "what:" { append Attributes(body) $val } "details:" { append Attributes(body) $val } "duration:" { set Attributes(duration) $val } "period:" { set Attributes(period) $val } "ntimes:" { set Attributes(ntimes) $val } "attributes:" { set Attributes(action) $val } } } if {[info exists Attributes(action)]} { # Nuke quotes and commas in action regsub -all {[,\"]} $Attributes(action) { } Attributes(action) # Add spaces to pairs regsub -all \}\{ $Attributes(action) \}\ \{ Attributes(action) # Add another pair of brackets to make a proper list set Attributes(action) "{$Attributes(action)}" # Convert to a real Tcl list eval set Attributes(action) $Attributes(action) } # Split out date into month, day, year, time parts scan $Attributes(date) "%s%s%s%s%s" wkday month day time year set time [string range $time 0 4] set Attributes(wkday) $wkday set Attributes(month) $FullMonth($month) set Attributes(day) $day set Attributes(time) $time set Attributes(year) $year # Convert newlines in body to spaces set body $Attributes(body) regsub -all "\n" $body " " body # TODO: Escape BODY to get rid of [] chars. set Attributes(body) $body # Convert to Reminder format convertReminder } #*********************************************************************** # %PROCEDURE: convertReminder # %ARGUMENTS: # None -- uses global Attributes variable which must be filled in # %RETURNS: # Nothing # %DESCRIPTION: # Converts a reminder to Remind format. #*********************************************************************** proc convertReminder {} { global Attributes switch -exact $Attributes(period) { single { convertSingleReminder } daily { convertDailyReminder } weekly { convertWeeklyReminder } monthly { convertMonthlyReminder } yearly { convertYearlyReminder } default { puts "\# Unable to convert reminder with period $Attributes(period)" puts "\# Body is: $Attributes(body)" } } } #*********************************************************************** # %PROCEDURE: convertSingleReminder # %ARGUMENTS: # None -- uses global Attributes variable which must be filled in # %RETURNS: # Nothing # %DESCRIPTION: # Converts a reminder with "single" period to Remind format. #*********************************************************************** proc convertSingleReminder {} { global Attributes puts "REM $Attributes(day) $Attributes(month) $Attributes(year) [at][duration]MSG $Attributes(body)" } #*********************************************************************** # %PROCEDURE: convertDailyReminder # %ARGUMENTS: # None -- uses global Attributes variable which must be filled in # %RETURNS: # Nothing # %DESCRIPTION: # Converts a reminder with "daily" period to Remind format. #*********************************************************************** proc convertDailyReminder {} { global Attributes set ntimes [expr $Attributes(ntimes) - 1] if {$ntimes <= 1} { convertSingleReminder return } set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) $ntimes] puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *1 [at][duration]UNTIL $until MSG $Attributes(body)" } #*********************************************************************** # %PROCEDURE: convertWeeklyReminder # %ARGUMENTS: # None -- uses global Attributes variable which must be filled in # %RETURNS: # Nothing # %DESCRIPTION: # Converts a reminder with "daily" period to Remind format. #*********************************************************************** proc convertWeeklyReminder {} { global Attributes set ntimes [expr $Attributes(ntimes) - 1] if {$ntimes <= 1} { convertSingleReminder return } set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 7]] puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *7 [at][duration]UNTIL $until MSG $Attributes(body)" } #*********************************************************************** # %PROCEDURE: convertMonthlyReminder # %ARGUMENTS: # None -- uses global Attributes variable which must be filled in # %RETURNS: # Nothing # %DESCRIPTION: # Converts a reminder with "monthly" period to Remind format. #*********************************************************************** proc convertMonthlyReminder {} { global Attributes set ntimes [expr $Attributes(ntimes) - 1] if {$ntimes <= 1} { convertSingleReminder return } # If repetition > 1000, it's infinite if {$ntimes > 1000} { puts "REM $Attributes(day) [at][duration]MSG $Attributes(body)" return } ### UNTIL date is fudged! set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 30]] puts "REM $Attributes(day) [at][duration]UNTIL $until MSG $Attributes(body)" } #*********************************************************************** # %PROCEDURE: convertYearlyReminder # %ARGUMENTS: # None -- uses global Attributes variable which must be filled in # %RETURNS: # Nothing # %DESCRIPTION: # Converts a reminder with "yearly" period to Remind format. #*********************************************************************** proc convertYearlyReminder {} { global Attributes # No special handling of ntimes et al. puts "REM $Attributes(day) $Attributes(month) [at][duration]MSG $Attributes(body)" } #*********************************************************************** # %PROCEDURE: at # %ARGUMENTS: # None -- uses Attributes global variable # %RETURNS: # A string providing the correct AT clause for a timed reminder. #*********************************************************************** proc at {} { global Attributes if {![info exists Attributes(time)]} { return "" } if {"$Attributes(time)" == ""} { return "" } return "AT $Attributes(time) " } #*********************************************************************** # %PROCEDURE: duration # %ARGUMENTS: # None -- uses Attributes global variable # %RETURNS: # A string providing the correct DURATION clause for a timed reminder. #*********************************************************************** proc duration {} { global Attributes if {![info exists Attributes(duration)]} { return "" } if {"$Attributes(duration)" == ""} { return "" } set h [expr $Attributes(duration) / 3600] set remainder [expr $Attributes(duration) - $h*3600] set m [expr $remainder / 60] return "DURATION [format "%d:%02d " $h $m]" } #*********************************************************************** # %PROCEDURE: getUntilDate # %ARGUMENTS: # day, month, year -- a date # days -- number of days to add to date # %RETURNS: # The date which is "days" later than supplied date in a correct UNTIL # format. #*********************************************************************** proc getUntilDate { day month year days } { global RemindPipe global MonthNum set date "'$year/$MonthNum($month)/$day'" puts $RemindPipe "MSG \[trigger($date + $days)\]%" puts $RemindPipe "flush" flush $RemindPipe gets $RemindPipe line return $line } catch {wm withdraw .} # Start a Remind process to issue reminders if {[catch {set RemindPipe [open "|remind -" "r+"]} err]} { puts stderr "Error: Cannot run Remind: $err" exit 1 } puts $RemindPipe "banner %" flush $RemindPipe # Write some blurb puts "\# Reminder file converted from \"cm\" data by cm2rem.tcl" puts "" while {[gets stdin line] >= 0} { processLine $line } exit 0 remind-03.01.15/scripts/tkremind0000644000076400007640000025712012514120337014575 0ustar dfsdfs#!/bin/sh # -*-Mode: TCL;-*- #-------------------------------------------------------------- # TKREMIND # # A cheesy graphical front/back end for Remind using Tcl/Tk # # This file is part of REMIND. # Copyright (C) 1992-1998 Dianne Skoll # Copyright (C) 1999-2010 Roaring Penguin Software Inc. # #-------------------------------------------------------------- # the next line restarts using wish \ exec wish "$0" "$@" wm withdraw . # Our icon photo catch { image create photo rpicon -data { R0lGODlhFwAgAOecABUTERYTERYUERcVEhgWExkXFBkXFRoXFRsZFhwZFxwa GB0bGR4cGR4cGh8dGiAeHCEfHCEfHSIgHSIgHiQiHyYkISknJCooJispJywq Jy4sKTIwLjUzMDUzMTo4Njs5Nzs5ODw7ODw7OT07OT48OkE/PUJAPkNBP0RC QEVDQUVEQkdFQ0lIRkpJR01LSU5MSlBPTVFQTlNSUFRSUFRSUVVTUlVUUllY VltZV1xaWF1cWmBfXmJgX2RiYGZlY2dmZGppZ2tqaG1ram9tbHFwb3Jwb3Rz cXV0c3Z0c3Z1c3Z1dHd1dHh2dXh3dnt5eHx7eXx7en18en59e4B/foGAf4KB f4SDgYWEgoWEg4eGhIiHhouKiI2Mio6Ni46NjJCQj5KRkJSTkZeWlpiXlpmY l5qZmJybmp6dnKCfnqGgoKKhoKOioaSjoqinp6qpqKurqq+urbCvrrCwr7Gw r7OysbW1tLi3tri3t7u6ur28vMTDw8TEw8XFxMbFxcfGxsfHxsrJycrKyczM y83My83MzM3NzdDQz9LR0dPS0tPT09fX19jY19ra2dvb29zc29zc3Ojn5+jo 6Orq6uzs7O/v7/T09PX19fb29vf39/r6+vv7+/7+/v////////////////// //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// /////////////////////yH5BAEKAP8ALAAAAAAXACAAAAj+AP8JHEiwoMGD CAcusRAAQEKDBQIcEBAAwUODAQJAsBGAwsWCBzJuUBLgI0ENGVM2dACg5UWV KU+Y/JfRQBknPoq8ATQz4wxOQIFa6vMx5ZSgQetczJDSClKgcF6mFDEnE9I2 D0fADOChUdA1D7dmTBEUTditDQRQAnomIQaxICpoAmomoUoAGS2YIBIUDEIu YndI8FAJaBaEMlIuSEkloxugUBBOSLkh44AvGfkAPYJQpYqMLIQEILB205DO KW9kJHMhQAmgkaKgzsgjggM5GbEAxaNmdoAPOoz8CCAgEVAtg3wPEPMnQQAU QWsg5AAzDZSMbIBeaoHwAUwSDAI2XMAENA8ThAPEBvAStEkc3yonrOW0aUMk +BkBVAlaKATC8Fsp8Igid5ABgxMHtaTgggy6ZFBAADs= } wm iconphoto . -default rpicon } proc missing_tcllib { pkg } { catch { puts stderr "Could not find the '$pkg' package -- you must install tcllib.\nPlease see http://tcllib.sourceforge.net/" } tk_dialog .err "Error: tcllib not installed" "Could not find the '$pkg' package -- you must install tcllib. Please see http://tcllib.sourceforge.net/" error 0 OK exit 1 } if {[catch {package require mime}]} { missing_tcllib mime } if {[catch {package require smtp}]} { missing_tcllib smtp } # Check that we have the right version of wish if {$tcl_version < 8.0} { tk_dialog .error Error "You need wish version 8.0 or higher to run TkRemind; you have $tcl_version" error 0 OK exit 1 } if {$tcl_platform(platform) == "windows"} { tk_dialog .error Error "Please do not port Remind to Windows" error 0 OK exit 1 } #--------------------------------------------------------------------------- # GLOBAL VARIABLES #--------------------------------------------------------------------------- set Option(ConfirmQuit) 0 set OptDescr(ConfirmQuit) "(0/1) If 1, TkRemind prompts you to confirm 'Quit' operation" set Option(AutoClose) 1 set OptDescr(AutoClose) "(0/1) If 1, TkRemind automatically closes pop-up reminders after a minute" set Option(RingBell) 0 set OptDescr(RingBell) "(0/1) If 1, TkRemind beeps the terminal when a pop-up reminder appears" set Option(StartIconified) 0 set OptDescr(StartIconified) "(0/1) If 1, TkRemind starts up in the iconified state" set Option(Deiconify) 0 set OptDescr(Deiconify) "(0/1) If 1, TkRemind deiconifies the calendar window when a reminder pops up" set Option(ShowTodaysReminders) 1 set OptDescr(ShowTodaysReminders) "(0/1) If 1, TkRemind shows all of today's non-timed reminders in a window at startup and when the date changes" set Option(RunCmd) "" set OptDescr(RunCmd) "(String) If non-blank, run specified command when a pop-up reminder appears" set Option(FeedReminder) 0 set OptDescr(FeedReminder) "(0/1) If 1, feed the reminder to RunCmd on standard input (see RunCmd option)" set Option(Editor) "emacs +%d %s" set OptDescr(Editor) "(String) Specify command to edit a file. %d is replaced with line number and %s with filename" set Option(MailAddr) "" set OptDescr(MailAddr) "(String) Specify an e-mail address to which reminders should be sent if the popup window is not manually dismissed" set Option(SMTPServer) "127.0.0.1" set OptDescr(SMTPServer) "(String) IP address or host name of SMTP server to use for sending e-mail" # Remind program to execute -- supply full path if you want set Remind "remind" #set Remind "/home/dfs/Remind/src/remind" # Rem2PS program to execute -- supply full path if you want set Rem2PS "rem2ps" # Reminder file to source -- default set ReminderFile {NOSUCHFILE} set ReminderFile [file nativename "~/.reminders"] set EditorPid -1 # Reminder file to append to -- default set AppendFile {NOSUCHFILE} catch {set AppendFile $ReminderFile} set SetFontsWorked 0 #---------------- DON'T CHANGE STUFF BELOW HERE ------------------ # 24-hour clock mode set TwentyFourHourMode 0 # Is Monday in first column? set MondayFirst 0 # Month names in English set MonthNames {January February March April May June July August September October November December} # Day names in Remind's pre-selected language set DayNames {} # Day name in English set EnglishDayNames {Sunday Monday Tuesday Wednesday Thursday Friday Saturday} # Current month and year -- will be set by Initialize procedure set CurMonth -1 set CurYear -1 # Background reminder counter set BgCounter 0 # Absolutely today -- unlike the CurMonth and CurYear, these won't change set TodayMonth -1 set TodayYear -1 set TodayDay -1 # Reminder option types and skip types set OptionType 1 set SkipType 1 # Remind command line set CommandLine {} set PSCmd {} # Print options -- destination file; letter-size; landscape; fill page; default # encoding; 36pt margins; print small calendars set PrintDest file set PrintSize letter set PrintOrient landscape set PrintFill 1 set PrintEncoding 0 set PrintMargins 36pt set PrintSmallCalendars 1 # Highest tag seen so far. Array of tags is stored in ReminderTags() set HighestTagSoFar 0 #*********************************************************************** # %PROCEDURE: Initialize # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Initializes TkRemind -- sets day names, Remind command line, # MondayFirst flag, current date, etc. #*********************************************************************** proc Initialize {} { global DayNames argc argv CommandLine ReminderFile AppendFile Remind PSCmd global MondayFirst TwentyFourHourMode set CommandLine "|$Remind -itkremind=1 -p -y -l" set PSCmd "$Remind -p -l" set i 0 while {$i < $argc} { if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} { append CommandLine " [lindex $argv $i]" append PSCmd " [lindex $argv $i]" if {[regexp -- {m} [lindex $argv $i]]} { set MondayFirst 1 } if {"[lindex $argv $i]" == "-b1"} { set TwentyFourHourMode 1 } } else { break } incr i } if {$i < $argc} { set ReminderFile [lindex $argv $i] set AppendFile $ReminderFile incr i if {$i < $argc} { set AppendFile [lindex $argv $i] incr i } } # If reminder file is a directory and appendfile is the same as # reminder file, choose append file to be $ReminderFile/100-tkremind.rem if {[file isdirectory $ReminderFile]} { if {"$ReminderFile" == "$AppendFile"} { set AppendFile [file join $ReminderFile "100-tkremind.rem"] } } # Check system sanity if {! [file readable $ReminderFile]} { set ans [tk_dialog .error "TkRemind: Warning" "Can't read reminder file `$ReminderFile'" warning 0 "Create it and continue" "Exit"] if {$ans != 0} { exit 1 } catch {close [open "$ReminderFile" w]} } if {! [file readable $ReminderFile]} { tk_dialog .error "TkRemind: Error" "Could not create reminder file `$ReminderFile'" error 0 "Exit" exit 1 } if {[file isdirectory $ReminderFile] && ! [file exists $AppendFile]} { if {![catch {close [open "$AppendFile" "a"]}]} { tk_dialog .error "Created File" "Created blank file `$AppendFile'" info 0 "OK" } } if {! [file writable $AppendFile]} { tk_dialog .error Error "Can't write reminder file `$AppendFile'" error 0 Ok exit 1 } append CommandLine " $ReminderFile" append PSCmd " $ReminderFile" set DayNames [GetWeekdayNames] # puts "CommandLine: $CommandLine" } #--------------------------------------------------------------------------- # GetWeekdayNames - Spawn a remind process and get the names of the weekdays # Also sets CurMonth and CurYear. #--------------------------------------------------------------------------- proc GetWeekdayNames {} { global CurMonth CurYear TodayYear TodayMonth TodayDay Remind set f [open "|$Remind - 2>/dev/null" r+] puts $f "banner %" set i 0 while { $i < 7 } { puts $f "msg \[wkday($i)\]%" incr i } # Get current month and year as long as we're running Remind puts $f "msg %n%" puts $f "msg %y%" puts $f "msg %d%" puts $f "FLUSH" flush $f set ans {} set i 0 while { $i < 7 } { lappend ans [gets $f] incr i } set CurMonth [expr [gets $f] - 1] set CurYear [gets $f] set TodayDay [gets $f] set TodayMonth $CurMonth set TodayYear $CurYear close $f return $ans } #*********************************************************************** # %PROCEDURE: CalEntryOffset # %ARGUMENTS: # firstDay -- first day of month (0=Sunday, 6=Saturday) # %RETURNS: # Offset mapping day numbers (1-31) to window numbers (0-41) # %DESCRIPTION: # Computes offset from day number to window number #*********************************************************************** proc CalEntryOffset { firstDay } { global MondayFirst if {$MondayFirst} { incr firstDay -1 if {$firstDay < 0} { set firstDay 6 } } return [expr $firstDay-1] } #*********************************************************************** # %PROCEDURE: CreateCalFrame # %ARGUMENTS: # w -- name of frame window # dayNames -- names of weekdays # %RETURNS: # Nothing # %DESCRIPTION: # Creates a frame holding a grid of labels and a grid of text entries #*********************************************************************** proc CreateCalFrame { w dayNames } { # Figure out reasonable height for text frames global SetFontsWorked set h [winfo screenheight .] if {$h <= 480} { if {$SetFontsWorked} { set h 3 } else { set h 2 } } elseif {$h <= 600} { set h 4 } else { set h 5 } global MondayFirst frame $w for {set i 0} {$i < 7} {incr i} { if {$MondayFirst} { set index [expr ($i+1)%7] } else { set index $i } label $w.day$i -border 1 -text [lindex $dayNames $index] -justify center grid configure $w.day$i -row 0 -column $i -sticky ew } for {set i 0} {$i < 6} {incr i} { set n [expr $i*7] for {set j 0} {$j < 7} {incr j} { set f [expr $n+$j] button $w.l$f -text "" -justify center -command "" \ -state disabled -relief flat -border 0 -padx 0 -pady 0 text $w.t$f -width 12 -height $h -border 1 -spacing3 3 -wrap word -relief flat \ -state disabled -takefocus 0 -cursor {} $w.t$f tag bind TAGGED "EditTaggedReminder $w.t$f" $w.t$f tag bind REM "FireEditor $w.t$f" grid configure $w.l$f -row [expr $i*2+1] -column $j -sticky ew grid configure $w.t$f -row [expr $i*2+2] -column $j -sticky nsew } } for {set i 0} {$i < 7} {incr i} { grid columnconfigure $w $i -weight 1 } for {set i 2} {$i < 14} {incr i 2} { grid rowconfigure $w $i -weight 1 } } #*********************************************************************** # %PROCEDURE: ConfigureCalFrame # %ARGUMENTS: # w -- window name of calendar frame # firstDay -- first weekday of month # numDays -- number of days in month # %RETURNS: # Nothing # %DESCRIPTION: # Sets up button labels; configures text justification #*********************************************************************** proc ConfigureCalFrame { w firstDay numDays } { global CurMonth CurYear TodayMonth TodayYear TodayDay global tk_version set offset [CalEntryOffset $firstDay] set first [expr $offset+1] set last [expr $offset+$numDays] set bg [lindex [. configure -background] 3] for {set i 0} {$i < $first} {incr i} { grid $w.l$i $w.t$i $w.l$i configure -text "" -command "" -state disabled -relief flat $w.t$i configure -relief flat -takefocus 0 -state normal $w.t$i delete 1.0 end foreach t [$w.t$i tag names] { $w.t$i tag delete $t } $w.t$i tag bind TAGGED "EditTaggedReminder $w.t$i" $w.t$i tag bind REM "FireEditor $w.t$i" $w.t$i configure -state disabled $w.t$i configure -background $bg $w.l$i configure -background $bg } for {set i $first} {$i <= $last} {incr i} { grid $w.l$i $w.t$i set d [expr $i-$first+1] $w.l$i configure -text $d -state normal -relief flat \ -command "ModifyDay $d $firstDay" $w.t$i configure -relief sunken -takefocus 1 -state normal $w.t$i delete 1.0 end foreach t [$w.t$i tag names] { $w.t$i tag delete $t } $w.t$i tag bind TAGGED "EditTaggedReminder $w.t$i" $w.t$i tag bind REM "FireEditor $w.t$i" $w.t$i configure -state disabled $w.t$i configure -background $bg $w.l$i configure -background $bg } set forgetIt 0 for {set i [expr $last+1]} {$i < 42} {incr i} { if {$i%7 == 0} { set forgetIt 1 } set row [expr ($i/7)*2+1] if {$forgetIt} { grid remove $w.l$i $w.t$i grid rowconfigure $w $row -weight 0 grid rowconfigure $w [expr $row+1] -weight 0 } else { grid rowconfigure $w [expr $row+1] -weight 1 } $w.l$i configure -text "" -command "" -state disabled -relief flat $w.t$i configure -relief flat -takefocus 0 -state normal $w.t$i delete 1.0 end foreach t [$w.t$i tag names] { $w.t$i tag delete $t } $w.t$i tag bind TAGGED "EditTaggedReminder $w.t$i" $w.t$i tag bind REM "FireEditor $w.t$i" $w.t$i configure -state disabled $w.t$i configure -background $bg $w.l$i configure -background $bg } if { $CurMonth == $TodayMonth && $CurYear == $TodayYear } { set n [expr $TodayDay + $offset] $w.l$n configure -background "#00c0c0" } } #--------------------------------------------------------------------------- # CreateCalWindow -- create the calendar window. # Arguments: # dayNames -- names of weekdays in current language {Sun .. Sat} #--------------------------------------------------------------------------- proc CreateCalWindow { dayNames } { global Option frame .h label .h.title -text "" -justify center -pady 1 -border 1 -relief raised pack .h.title -side top -fill x pack .h -side top -expand 0 -fill x CreateCalFrame .cal $dayNames frame .b button .b.prev -text {<-} -command {MoveMonth -1} -border 1 button .b.this -text {Today} -command {ThisMonth} -border 1 button .b.next -text {->} -command {MoveMonth 1} -border 1 button .b.goto -text {Go To Date...} -command {GotoDialog} -border 1 button .b.print -text {Print...} -command {DoPrint} -border 1 button .b.quit -text {Quit} -command {Quit} -border 1 button .b.options -text {Options...} -command EditOptions -border 1 label .b.status -text "" -width 25 -relief sunken -border 1 label .b.nqueued -text "" -width 20 -relief sunken -border 1 pack .b.prev .b.this .b.next .b.goto .b.print .b.options .b.quit -side left -fill x pack .b.status -side left -fill x -expand 1 pack .b.nqueued -side left -fill x pack .b -side bottom -fill x -expand 0 pack .cal -side top -fill both -expand 1 wm title . "TkRemind" wm iconname . "" wm protocol . WM_DELETE_WINDOW Quit wm deiconify . bind . Quit bind . ".b.prev flash; .b.prev invoke" bind . ".b.next flash; .b.next invoke" bind . ".b.prev flash; .b.prev invoke" bind . ".b.next flash; .b.next invoke" bind . ".b.this flash; .b.this invoke" if {$Option(StartIconified)} { wm iconify . } update grid propagate .cal 0 } #*********************************************************************** # %PROCEDURE: EditOptions # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Lets user edit options #*********************************************************************** proc EditOptions {} { global Option tmpOpt # Make a working copy of current option set foreach name [array names Option] { set tmpOpt($name) $Option($name) } set w .opt catch { destroy $w } toplevel $w wm title $w "TkRemind Options" wm iconname $w "Options" frame $w.f frame $w.b pack $w.f -side top -expand 1 -fill both pack $w.b -side top -expand 0 -fill x # Start iconified checkbutton $w.startIconified -text "Start up Iconified" \ -anchor w -justify left \ -variable tmpOpt(StartIconified) # Show today's reminders on startup checkbutton $w.showTodays -text "Show Today's Reminders on Startup" \ -anchor w -justify left \ -variable tmpOpt(ShowTodaysReminders) # Confirm quit checkbutton $w.confirmQuit -text "Confirm Quit" -anchor w -justify left \ -variable tmpOpt(ConfirmQuit) # Bring down reminder windows after one minute checkbutton $w.bringDown \ -text "Automatically close pop-up reminders after a minute" \ -anchor w -justify left -variable tmpOpt(AutoClose) # Ring bell when popping up reminder checkbutton $w.ring -text "Beep terminal when popping up a reminder" \ -anchor w -justify left -variable tmpOpt(RingBell) checkbutton $w.deic -text "Deiconify calendar window when popping up a reminder" \ -anchor w -justify left -variable tmpOpt(Deiconify) # Run command when popping up reminder frame $w.rf label $w.rl -text "Run command when popping up reminder:" -anchor w \ -justify left entry $w.cmd -width 30 pack $w.rl -in $w.rf -side left -expand 0 -fill none pack $w.cmd -in $w.rf -side left -expand 1 -fill x $w.cmd insert 0 $tmpOpt(RunCmd) frame $w.sep3 -border 1 -relief sunken # E-mail reminder if popup not dismissed frame $w.eml label $w.lab_email_address -text "E-mail reminders here if popup not dismissed:" -anchor w -justify left entry $w.email_address -width 30 pack $w.lab_email_address -in $w.eml -side left -expand 0 -fill none pack $w.email_address -in $w.eml -side left -expand 1 -fill x $w.email_address insert 0 $tmpOpt(MailAddr) frame $w.fsmtp label $w.lab_smtp -text "Name or IP address of SMTP server:" -anchor w -justify left entry $w.smtp -width 30 pack $w.lab_smtp -in $w.fsmtp -side left -expand 0 -fill none pack $w.smtp -in $w.fsmtp -side left -expand 1 -fill x $w.smtp insert 0 $tmpOpt(SMTPServer) # Editor frame $w.ef label $w.el -text "Text Editor:" -anchor w -justify left entry $w.editor -width 30 pack $w.el -in $w.ef -side left -expand 0 -fill none pack $w.editor -in $w.ef -side left -expand 1 -fill x $w.editor insert 0 $tmpOpt(Editor) frame $w.sep1 -border 1 -relief sunken frame $w.sep2 -border 1 -relief sunken checkbutton $w.feed \ -text "Feed popped-up reminder to command's standard input" \ -variable tmpOpt(FeedReminder) -anchor w -justify left pack $w.startIconified -in $w.f -side top -expand 0 -fill x pack $w.showTodays -in $w.f -side top -expand 0 -fill x pack $w.confirmQuit -in $w.f -side top -expand 0 -fill x pack $w.bringDown -in $w.f -side top -expand 0 -fill x pack $w.ring -in $w.f -side top -expand 0 -fill x pack $w.deic -in $w.f -side top -expand 0 -fill x pack $w.sep1 -in $w.f -side top -expand 0 -fill x -ipady 1 pack $w.rf -in $w.f -side top -expand 0 -fill x pack $w.feed -in $w.f -side top -expand 0 -fill x pack $w.sep3 -in $w.f -side top -expand 0 -fill x -ipady 1 pack $w.eml -in $w.f -side top -expand 0 -fill x pack $w.fsmtp -in $w.f -side top -expand 0 -fill x pack $w.ef -in $w.f -side top -expand 0 -fill x pack $w.sep2 -in $w.f -side top -expand 0 -fill x -ipady 1 button $w.apply -text "Apply Options" -command "ApplyOptions $w; destroy $w" button $w.save -text "Save Options" -command "SaveOptions $w; destroy $w" button $w.cancel -text "Cancel" -command "destroy $w" pack $w.apply $w.save $w.cancel -in $w.b -side left -expand 0 -fill x CenterWindow $w } #*********************************************************************** # %PROCEDURE: ApplyOptions # %ARGUMENTS: # w -- edit options window path # %RETURNS: # Nothing # %DESCRIPTION: # Applies options set in the edit options box. #*********************************************************************** proc ApplyOptions { w } { global Option tmpOpt set tmpOpt(RunCmd) [$w.cmd get] set tmpOpt(Editor) [$w.editor get] set tmpOpt(MailAddr) [$w.email_address get] set tmpOpt(SMTPServer) [$w.smtp get] # Copy working copy to real option set foreach name [array names tmpOpt] { set Option($name) $tmpOpt($name) } } #*********************************************************************** # %PROCEDURE: SaveOptions # %ARGUMENTS: # w -- edit options window path # %RETURNS: # Nothing # %DESCRIPTION: # Saves options in $HOME/.tkremindrc #*********************************************************************** proc SaveOptions { w } { global Option OptDescr ApplyOptions $w set problem [catch {set f [open ~/.tkremindrc "w"]} err] if {$problem} { tk_dialog .error Error "Can't write ~/.tkremindrc: $err" 0 OK return } puts $f "# TkRemind option file -- created automatically" puts $f "# [clock format [clock seconds]]" puts $f "# Format of each line is 'key value' where 'key'" puts $f "# specifies the option name, and 'value' is a" puts $f "# *legal Tcl list element* specifying the option value." foreach name [lsort [array names Option]] { puts $f "" puts $f "# $OptDescr($name)" puts $f [list $name $Option($name)] } puts $f "" close $f } #*********************************************************************** # %PROCEDURE: LoadOptions # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Loads options from ~/.tkremindrc #*********************************************************************** proc LoadOptions {} { global Option set problem [catch {set f [open "~/.tkremindrc" "r"]}] if {$problem} { return } while {[gets $f line] >= 0} { if {[string match "#*" $line]} { continue } if {$line == ""} { continue } foreach {key val} $line {} if {![info exists Option($key)]} { puts "Unknown option in ~/.tkremindrc: $key" continue } set Option($key) $val } close $f } #*********************************************************************** # %PROCEDURE: ConfigureCalWindow # %ARGUMENTS: # month -- month name # year -- the year # firstDay -- first day in month # numDays -- number of days in month # %RETURNS: # Nothing # %DESCRIPTION: # Configures the calendar window for a month and year # %PRECONDITIONS: # Any preconditions # %POSTCONDITIONS: # Any postconditions # %SIDE EFFECTS: # Any side effects #*********************************************************************** proc ConfigureCalWindow { month year firstDay numDays } { .h.title configure -text "$month $year" wm title . "$month $year - TkRemind" wm iconname . "$month $year" ConfigureCalFrame .cal $firstDay $numDays } #--------------------------------------------------------------------------- # FillCalWindow -- Fill in the calendar for global CurMonth and CurYear. #--------------------------------------------------------------------------- proc FillCalWindow {} { set FileName "" set LineNo 0 global DayNames CurYear CurMonth MonthNames CommandLine Status "Firing off Remind..." set month [lindex $MonthNames $CurMonth] set file [open "$CommandLine $month $CurYear" r] # Look for # rem2ps begin line while { [gets $file line] >= 0 } { if { [string compare "$line" "# rem2ps begin"] == 0 } { break } } if { [string compare "$line" "# rem2ps begin"] != 0 } { Status "Problem reading results from Remind!" after 5000 DisplayTime catch { close $file } return 0 } # Read month name, year, number of days in month, first weekday, Mon flag gets $file line regexp {^([^ ]*) ([0-9][0-9][0-9][0-9]) ([0-9][0-9]?) ([0-9]) ([0-9])} $line dummy monthName year daysInMonth firstWkday mondayFirst # Skip day names -- we already have them gets $file line ConfigureCalWindow $monthName $year $firstWkday $daysInMonth set offset [CalEntryOffset $firstWkday] set fntag "x" while { [gets $file line] >= 0 } { # File info if { [ string match "# fileinfo *" $line ] } { regexp {fileinfo ([0-9]+) (.*)} $line all LineNo Filename set fntag "FILE_${LineNo}_${Filename}" } # Skip comments if { [string match "#*" $line] } { continue } if { [regexp {^([0-9][0-9][0-9][0-9])/([0-9][0-9])/([0-9][0-9]) +([^ ]+) +([^ ]+) +[^ ]+ +[^ ]+(.*)} $line all year month day type tag stuff] == 0 } { continue } set day [string trimleft $day 0] set n [expr $day+$offset] set month [string trimleft $month 0] set extratags "" switch -exact -- $type { "WEEK" { set stuff [string trimleft $stuff] set stuff [string trimright $stuff] set label [expr $firstWkday + $day - 1] .cal.l$label configure -text "$day $stuff" continue } "SHADE" { DoShadeSpecial $n $stuff continue } "MOON" { DoMoonSpecial $n $stuff continue } "COLOUR" - "COLOR" { if {[regexp {^ *([0-9]+) +([0-9]+) +([0-9]+) +(.*)$} $stuff all r g b rest]} { if {$r > 255} { set r 255 } elseif {$r < 0} { set r 0 } if {$g > 255} { set g 255 } elseif {$g < 0} { set g 0 } if {$b > 255} { set b 255 } elseif {$b < 0} { set b 0 } set color [format "%02X%02X%02X" $r $g $b] set extratags "clr$color" .cal.t$n configure -state normal .cal.t$n tag configure $extratags -foreground "#$color" .cal.t$n configure -state disabled set stuff $rest } } } if { $type != "*" && $type != "COLOR" && $type != "COLOUR"} { continue } .cal.t$n configure -state normal if {[regexp {TKTAG([0-9]+)} $tag all tagno]} { .cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" $extratags $fntag] .cal.t$n tag bind "TKTAG$tagno" "TaggedEnter .cal.t$n" .cal.t$n tag bind "TKTAG$tagno" "TaggedLeave .cal.t$n" } else { .cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag] } .cal.t$n insert end "\n" .cal.t$n configure -state disabled } set problem [catch { close $file } errmsg] if {$problem} { tk_dialog .error Error "There was a problem running Remind: $errmsg" error 0 OK } DisplayTime } #--------------------------------------------------------------------------- # MoveMonth -- move by +1 or -1 months # Arguments: # delta -- +1 or -1 -- months to move. #--------------------------------------------------------------------------- proc MoveMonth {delta} { global CurMonth CurYear set CurMonth [expr $CurMonth + $delta] if {$CurMonth < 0} { set CurMonth 11 set CurYear [expr $CurYear-1] } if {$CurMonth > 11} { set CurMonth 0 incr CurYear } FillCalWindow } #--------------------------------------------------------------------------- # ThisMonth -- move to current month #--------------------------------------------------------------------------- proc ThisMonth {} { global CurMonth CurYear TodayMonth TodayYear # Do nothing if already there if { $CurMonth == $TodayMonth && $CurYear == $TodayYear } { return 0; } set CurMonth $TodayMonth set CurYear $TodayYear FillCalWindow } #--------------------------------------------------------------------------- # Status -- set status string # Arguments: # stuff -- what to set string to. #--------------------------------------------------------------------------- proc Status { stuff } { catch { .b.status configure -text $stuff } update idletasks } #--------------------------------------------------------------------------- # DoPrint -- print a calendar # Arguments: # None #--------------------------------------------------------------------------- proc DoPrint {} { global PrintDest PrintSize PrintMargins PrintOrient PrintFill PrintEncoding PrintSmallCalendars PrintStatus Rem2PS PSCmd global CurMonth CurYear MonthNames catch {destroy .p} toplevel .p wm title .p "TkRemind Print..." wm iconname .p "Print..." frame .p.f1 -relief sunken -border 2 frame .p.f11 frame .p.f12 frame .p.f2 -relief sunken -border 2 frame .p.f2a -relief sunken -border 2 frame .p.f3 -relief sunken -border 2 frame .p.f3a -relief sunken -border 2 frame .p.f4 radiobutton .p.tofile -text "To file: " -variable PrintDest -value file entry .p.filename button .p.browse -text "Browse..." -command PrintFileBrowse radiobutton .p.tocmd -text "To command: " -variable PrintDest -value command entry .p.command .p.command insert end "lpr" label .p.size -text "Paper Size:" radiobutton .p.letter -text "Letter" -variable PrintSize -value letter radiobutton .p.a4 -text "A4" -variable PrintSize -value a4 label .p.margin -text "Margins:" radiobutton .p.24pt -text "24pt margins" -variable PrintMargins -value 24pt radiobutton .p.36pt -text "36pt margins" -variable PrintMargins -value 36pt radiobutton .p.48pt -text "48pt margins" -variable PrintMargins -value 48pt label .p.orient -text "Orientation:" radiobutton .p.landscape -text "Landscape" -variable PrintOrient -value landscape radiobutton .p.portrait -text "Portrait" -variable PrintOrient -value portrait checkbutton .p.fill -text "Fill page" -variable PrintFill checkbutton .p.encoding -text "ISO 8859-1 PostScript encoding" -variable PrintEncoding checkbutton .p.calendars -text "Print small calendars" -variable PrintSmallCalendars button .p.print -text "Print" -command {set PrintStatus print} button .p.cancel -text "Cancel" -command {set PrintStatus cancel} pack .p.f1 .p.f2 .p.f2a .p.f3 .p.f3a \ -side top -fill both -expand 1 -anchor w pack .p.fill .p.encoding .p.calendars -in .p.f3a \ -side top -anchor w -fill none -expand 0 pack .p.f4 -side top -fill both -expand 1 -anchor w pack .p.f11 .p.f12 -in .p.f1 -side top -fill none -expand 0 -anchor w pack .p.tofile .p.filename .p.browse -in .p.f11 -side left -fill none -expand 0 -anchor w pack .p.tocmd .p.command -in .p.f12 -side left -fill none -expand 0 -anchor w pack .p.size .p.letter .p.a4 -in .p.f2 -side top -fill none -expand 0 -anchor w pack .p.margin .p.24pt .p.36pt .p.48pt -in .p.f2a -side top -anchor w -fill none -expand 0 pack .p.orient .p.landscape .p.portrait -in .p.f3 -side top -fill none -expand 0 -anchor w pack .p.print .p.cancel -in .p.f4 -side left -fill none -expand 0 bind .p ".p.cancel flash; .p.cancel invoke" bind .p ".p.print flash; .p.print invoke" set PrintStatus 2 CenterWindow .p tkwait visibility .p set oldFocus [focus] focus .p.filename grab .p tkwait variable PrintStatus catch {focus $oldFocus} set fname [.p.filename get] set cmd [.p.command get] destroy .p if {$PrintStatus == "cancel"} { return } if {$PrintDest == "file"} { if {$fname == ""} { tk_dialog .error Error "No filename specified" error 0 Ok return } if {[file isdirectory $fname]} { tk_dialog .error Error "$fname is a directory" error 0 Ok return } if {[file readable $fname]} { set ans [tk_dialog .error Overwrite? "Overwrite $fname?" question 0 No Yes] if {$ans == 0} { return } } set fname "> $fname" } else { set fname "| $cmd" } # Build the command line set cmd "$PSCmd 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS" if {$PrintSize == "letter"} { append cmd " -m Letter" } else { append cmd " -m A4" } if {$PrintMargins == "24pt"} { append cmd " -or 24 -ol 24 -ot 24 -ob 24" } elseif {$PrintMargins == "36pt"} { append cmd " -or 36 -ol 36 -ot 36 -ob 36" } else { append cmd " -or 48 -ol 48 -ot 48 -ob 48" } if {$PrintOrient == "landscape"} { append cmd " -l" } if {$PrintFill} { append cmd " -e" } if {$PrintEncoding} { append cmd " -i" } if {$PrintSmallCalendars} { append cmd " -c3" } else { append cmd " -c0" } append cmd " $fname" Status "Printing..." if {[catch {eval "exec $cmd"} err]} { tk_dialog .error Error "Error during printing: $err" error 0 Ok } DisplayTime } #--------------------------------------------------------------------------- # PrintFileBrowse -- browse for a filename for Print dialog # Arguments: none #--------------------------------------------------------------------------- proc PrintFileBrowse {} { set ans [BrowseForFile .filebrowse "Print to file..." "Ok" 0 "*.ps"] if {$ans != ""} { .p.filename delete 0 end .p.filename insert end $ans .p.filename icursor end .p.filename xview end } } #--------------------------------------------------------------------------- # GotoDialog -- Do the "Goto..." dialog #--------------------------------------------------------------------------- proc GotoDialog {} { global CurMonth MonthNames CurYear catch { destroy .g } set month [lindex $MonthNames $CurMonth] toplevel .g wm title .g "Go To Date" menubutton .g.mon -text "$month" -menu .g.mon.menu -relief raised menu .g.mon.menu -tearoff 0 foreach m $MonthNames { .g.mon.menu add command -label $m -command ".g.mon configure -text $m" } frame .g.y label .g.y.lab -text "Year: " entry .g.y.e -width 4 .g.y.e insert end $CurYear bind .g.y.e ".g.b.go flash; .g.b.go invoke" frame .g.b button .g.b.go -text "Go" -command {DoGoto} button .g.b.cancel -text "Cancel" -command { destroy .g } pack .g.b.go .g.b.cancel -expand 1 -fill x -side left pack .g.mon -fill x -expand 1 pack .g.y.lab -side left pack .g.y.e -side left -fill x -expand 1 pack .g.y -expand 1 -fill x pack .g.b -expand 1 -fill x bind .g ".g.b.cancel flash; .g.b.cancel invoke" CenterWindow .g set oldFocus [focus] grab .g focus .g.y.e tkwait window .g catch {focus $oldFocus} } #--------------------------------------------------------------------------- # DoGoto -- go to specified date #--------------------------------------------------------------------------- proc DoGoto {} { global CurYear CurMonth MonthNames set year [.g.y.e get] if { ! [regexp {^[0-9]+$} $year] } { tk_dialog .error Error {Illegal year specified (1990-5990)} error 0 Ok return } if { $year < 1990 || $year > 5990 } { tk_dialog .error Error {Illegal year specified (1990-5990)} error 0 Ok return } set month [lsearch -exact $MonthNames [.g.mon cget -text]] set CurMonth $month set CurYear $year destroy .g FillCalWindow } #--------------------------------------------------------------------------- # Quit -- handle the Quit button #--------------------------------------------------------------------------- proc Quit {} { global Option if { !$Option(ConfirmQuit) } { destroy . StopBackgroundRemindDaemon exit } if { [tk_dialog .question "Confirm..." {Really quit?} question 0 No Yes] } { destroy . StopBackgroundRemindDaemon exit } } #--------------------------------------------------------------------------- # CreateModifyDialog -- create dialog for adding a reminder # Arguments: # w -- path of parent window # day -- day number of month # firstDay -- day number of first day of month # args -- buttons to add to bottom frame. First sets result to 1, next # to 2, and so on. FIRST BUTTON MUST BE "Cancel" #--------------------------------------------------------------------------- proc CreateModifyDialog {w day firstDay args} { # Set up: Year, Month, Day, WeekdayName global CurYear CurMonth EnglishDayNames MonthNames OptionType SkipType global ModifyDialogResult TwentyFourHourMode set OptionType 1 set SkipType 1 set year $CurYear set month [lindex $MonthNames $CurMonth] set wkday [lindex $EnglishDayNames [expr ($day+$firstDay-1) % 7]] frame $w.o -border 4 -relief ridge frame $w.o1 -border 4 frame $w.o2 -border 4 frame $w.o3 -border 4 frame $w.exp -border 4 frame $w.adv -border 4 frame $w.weekend -border 4 frame $w.durationbox -border 4 frame $w.time -border 4 frame $w.hol -border 4 frame $w.msg frame $w.buttons pack $w.o1 $w.o2 $w.o3 -side top -anchor w -in $w.o pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 1 -fill both pack $w.buttons -side top -anchor w -pady 4 -expand 1 -fill x # TYPE 1 REMINDER radiobutton $w.type1 -variable OptionType -value 1 menubutton $w.day1 -text $day -relief raised -menu $w.day1.menu CreateDayMenu $w.day1 menubutton $w.mon1 -text $month -relief raised -menu $w.mon1.menu CreateMonthMenu $w.mon1 menubutton $w.year1 -text $year -relief raised -menu $w.year1.menu CreateYearMenu $w.year1 checkbutton $w.repbut -text "and repeating every" $w.repbut deselect menubutton $w.repdays -text 1 -relief raised -menu $w.repdays.menu CreateDayMenu $w.repdays 1 28 0 label $w.label1a -text "day(s) thereafter" pack $w.type1 $w.day1 $w.mon1 $w.year1 $w.repbut $w.repbut $w.repdays $w.label1a -side left -anchor w -in $w.o1 # TYPE 2 REMINDER radiobutton $w.type2 -variable OptionType -value 2 label $w.label2a -text First menubutton $w.wkday2 -text $wkday -relief raised -menu $w.wkday2.menu CreateWeekdayMenu $w.wkday2 label $w.label2b -text "on or after" menubutton $w.day2 -text $day -relief raised -menu $w.day2.menu CreateDayMenu $w.day2 1 31 0 menubutton $w.mon2 -text $month -relief raised -menu $w.mon2.menu CreateMonthMenu $w.mon2 menubutton $w.year2 -text $year -relief raised -menu $w.year2.menu CreateYearMenu $w.year2 pack $w.type2 $w.label2a $w.wkday2 $w.label2b $w.day2 $w.mon2 $w.year2 -side left -anchor w -in $w.o2 # TYPE 3 REMINDER if { $day <= 7 } { set which "First" } elseif {$day <= 14} { set which "Second" } elseif {$day <= 21} { set which "Third" } elseif {$day <= 28} { set which "Fourth" } else { set which "Last" } radiobutton $w.type3 -variable OptionType -value 3 menubutton $w.ordinal -text $which -relief raised -menu $w.ordinal.menu menu $w.ordinal.menu -tearoff 0 $w.ordinal.menu add command -label "First" -command "$w.ordinal configure -text First" $w.ordinal.menu add command -label "Second" -command "$w.ordinal configure -text Second" $w.ordinal.menu add command -label "Third" -command "$w.ordinal configure -text Third" $w.ordinal.menu add command -label "Fourth" -command "$w.ordinal configure -text Fourth" $w.ordinal.menu add command -label "Last" -command "$w.ordinal configure -text Last" $w.ordinal.menu add command -label "Every" -command "$w.ordinal configure -text Every" menubutton $w.wkday3 -text $wkday -relief raised -menu $w.wkday3.menu CreateWeekdayMenu $w.wkday3 label $w.label3 -text "in" menubutton $w.mon3 -text $month -relief raised -menu $w.mon3.menu CreateMonthMenu $w.mon3 menubutton $w.year3 -text $year -relief raised -menu $w.year3.menu CreateYearMenu $w.year3 pack $w.type3 $w.ordinal $w.wkday3 $w.label3 $w.mon3 $w.year3 -side left -anchor w -in $w.o3 # EXPIRY DATE checkbutton $w.expbut -text "Expire after" $w.expbut deselect menubutton $w.expday -text $day -relief raised -menu $w.expday.menu CreateDayMenu $w.expday 1 31 0 menubutton $w.expmon -text $month -relief raised -menu $w.expmon.menu CreateMonthMenu $w.expmon 0 menubutton $w.expyear -text $year -relief raised -menu $w.expyear.menu CreateYearMenu $w.expyear 0 pack $w.expbut $w.expday $w.expmon $w.expyear -side left -anchor w -in $w.exp # ADVANCE NOTICE checkbutton $w.advbut -text "Issue" $w.advbut deselect menubutton $w.advdays -text 3 -menu $w.advdays.menu -relief raised CreateDayMenu $w.advdays 1 10 0 label $w.advlab -text "day(s) in advance" checkbutton $w.advcount -text "not counting holidays/weekend" $w.advcount select pack $w.advbut $w.advdays $w.advlab $w.advcount -side left -anchor w -in $w.adv # WEEKEND label $w.weeklab -text "Weekend is: " pack $w.weeklab -side left -anchor w -in $w.weekend foreach d $EnglishDayNames { checkbutton $w.d$d -text $d $w.d$d deselect pack $w.d$d -side left -anchor w -in $w.weekend } $w.dSaturday select $w.dSunday select # TIMED REMINDER checkbutton $w.timebut -text "Timed reminder at" $w.timebut deselect menubutton $w.timehour -text "12" -menu $w.timehour.menu -relief raised if {$TwentyFourHourMode} { CreateDayMenu $w.timehour 0 23 0 } else { CreateDayMenu $w.timehour 1 12 0 } menubutton $w.timemin -text "00" -menu $w.timemin.menu -relief raised menu $w.timemin.menu -tearoff 0 foreach i {00 05 10 15 20 25 30 35 40 45 50 55} { $w.timemin.menu add command -label $i \ -command "$w.timemin configure -text $i" } if {!$TwentyFourHourMode} { menubutton $w.ampm -text "PM" -menu $w.ampm.menu -relief raised menu $w.ampm.menu -tearoff 0 $w.ampm.menu add command -label "AM" -command "$w.ampm configure -text {AM}" $w.ampm.menu add command -label "PM" -command "$w.ampm configure -text {PM}" } checkbutton $w.timeadvbut -text "with" $w.timeadvbut deselect menubutton $w.timeadv -text "15" -menu $w.timeadv.menu -relief raised menu $w.timeadv.menu -tearoff 0 foreach i {5 10 15 30 45 60} { $w.timeadv.menu add command -label $i -command "$w.timeadv configure -text $i" } label $w.timelab1 -text "minutes advance notice" checkbutton $w.timerepbut -text "repeated every" $w.timerepbut deselect menubutton $w.timerep -text "5" -menu $w.timerep.menu -relief raised menu $w.timerep.menu -tearoff 0 foreach i {3 5 10 15 30} { $w.timerep.menu add command -label $i -command "$w.timerep configure -text $i" } label $w.timelab2 -text "minutes" if {$TwentyFourHourMode} { pack $w.timebut $w.timehour $w.timemin $w.timeadvbut $w.timeadv $w.timelab1 $w.timerepbut $w.timerep $w.timelab2 -side left -anchor w -in $w.time } else { pack $w.timebut $w.timehour $w.timemin $w.ampm $w.timeadvbut $w.timeadv $w.timelab1 $w.timerepbut $w.timerep $w.timelab2 -side left -anchor w -in $w.time } # DURATION checkbutton $w.durationbut -text "Duration" $w.durationbut deselect menubutton $w.durationh -text "1" -menu $w.durationh.menu -relief raised menu $w.durationh.menu -tearoff 0 foreach i {0 1 2 3 4 5 6 7 8 9 10 11 12} { $w.durationh.menu add command -label $i -command "$w.durationh configure -text $i" } label $w.durationcolon -text ":" menubutton $w.durationm -text "00" -menu $w.durationm.menu -relief raised menu $w.durationm.menu -tearoff 0 foreach i {00 15 30 45} { $w.durationm.menu add command -label $i -command "$w.durationm configure -text $i" } pack $w.durationbut $w.durationh $w.durationcolon $w.durationm -side left -anchor w -in $w.durationbox # SKIP TYPE label $w.labhol -text "On holidays or weekends:" radiobutton $w.issue -variable SkipType -value 1 -text "Issue reminder as usual" radiobutton $w.skip -variable SkipType -value 2 -text "Skip reminder" radiobutton $w.before -variable SkipType -value 3 -text "Move reminder before holiday or weekend" radiobutton $w.after -variable SkipType -value 4 -text "Move reminder after holiday or weekend" pack $w.labhol $w.issue $w.skip $w.before $w.after -side top -anchor w -in $w.hol # TEXT ENTRY label $w.msglab -text "Body:" entry $w.entry pack $w.msglab -side left -anchor w -in $w.msg pack $w.entry -side left -anchor w -expand 1 -fill x -in $w.msg # BUTTONS set nbut 0 foreach but $args { incr nbut button $w.but$nbut -text $but -command "set ModifyDialogResult $nbut" pack $w.but$nbut -side left -anchor w -in $w.buttons -expand 1 -fill x } bind $w "$w.but1 flash; $w.but1 invoke" if {$nbut >= 2} { bind $w.entry "$w.but2 flash; $w.but2 invoke" } set ModifyDialogResult 0 # Center the window on the root CenterWindow $w } #*********************************************************************** # %PROCEDURE: RemindDialogToOptions # %ARGUMENTS: # w -- dialog window # %RETURNS: # A list of flag/value pairs representing the current state of # the "create reminder" dialog. #*********************************************************************** proc RemindDialogToOptions { w } { global OptionType SkipType repbut expbut advbut advcount global timebut timeadvbut timerepbut durationbut global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday set ans {} lappend ans "-global-OptionType" $OptionType lappend ans "-global-SkipType" $SkipType foreach win [winfo children $w] { set winstem [winfo name $win] switch -exact -- [winfo class $win] { "Menubutton" { lappend ans "-text-$winstem" [$win cget -text] } "Checkbutton" { lappend ans "-global-$winstem" [eval set $winstem] } "Entry" { lappend ans "-entry-$winstem" [string map -nocase {"\n" " "} [$win get]] } } } return $ans } #*********************************************************************** # %PROCEDURE: OptionsToRemindDialog # %ARGUMENTS: # w -- Remind dialog window # opts -- option list set by RemindDialogToOptions # %RETURNS: # Nothing # %DESCRIPTION: # Sets parameters in the dialog box according to saved options. #*********************************************************************** proc OptionsToRemindDialog { w opts } { global OptionType SkipType repbut expbut advbut advcount global timebut timeadvbut timerepbut TwentyFourHourMode durationbut global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday set hour "" set ampm "" foreach {flag value} $opts { switch -glob -- $flag { "-text-*" { set win [string range $flag 6 end] catch { $w.$win configure -text $value } if {"$flag" == "-text-ampm"} { set ampm $value } elseif {"$flag" == "-text-timehour"} { set hour $value } } "-global-*" { set win [string range $flag 8 end] set $win $value } "-entry-*" { set win [string range $flag 7 end] $w.$win delete 0 end $w.$win insert end $value } } } if {"$hour" != ""} { if {$TwentyFourHourMode} { if {"$ampm" != ""} { if {"$ampm" == "PM" && $hour < 12} { incr hour 12; $w.timehour configure -text $hour } } } else { if {$hour > 12} { incr hour -12 $w.timehour configure -text $hour $w.ampm configure -text "PM" } else { if {"$ampm" == ""} { $w.ampm configure -text "AM" } } } } } #--------------------------------------------------------------------------- # CreateMonthMenu -- create a menu with all the months of the year # Arguments: # w -- menu button -- becomes parent of menu # every -- if true, include an "every month" entry #--------------------------------------------------------------------------- proc CreateMonthMenu {w {every 1}} { global MonthNames menu $w.menu -tearoff 0 if {$every} { $w.menu add command -label "every month" -command "$w configure -text {every month}" } foreach month $MonthNames { $w.menu add command -label $month -command "$w configure -text $month" } } #--------------------------------------------------------------------------- # CreateWeekdayMenu -- create a menu with all the weekdays # Arguments: # w -- menu button -- becomes parent of menu #--------------------------------------------------------------------------- proc CreateWeekdayMenu {w} { global EnglishDayNames menu $w.menu -tearoff 0 foreach d $EnglishDayNames { $w.menu add command -label $d -command "$w configure -text $d" } $w.menu add command -label "weekday" -command "$w configure -text weekday" } #--------------------------------------------------------------------------- # CreateDayMenu -- create a menu with entries 1-31 and possibly "every day" # Arguments: # w -- menu button -- becomes parent of menu # min -- minimum day to start from. # max -- maximum day to go up to # every -- if true, include an "every day" entry #--------------------------------------------------------------------------- proc CreateDayMenu {w {min 1} {max 31} {every 1}} { menu $w.menu -tearoff 0 if {$every} { $w.menu add command -label "every day" -command "$w configure -text {every day}" } set d $min while { $d <= $max } { $w.menu add command -label $d -command "$w configure -text $d" incr d } } #--------------------------------------------------------------------------- # CreateYearMenu -- create a menu with entries from this year to this year+10 # and possibly "every year" # Arguments: # w -- menu button -- becomes parent of menu # every -- if true, include an "every year" entry #--------------------------------------------------------------------------- proc CreateYearMenu {w {every 1}} { menu $w.menu -tearoff 0 if {$every} { $w.menu add command -label "every year" -command "$w configure -text {every year}" } global CurYear set d $CurYear while { $d < [expr $CurYear + 11] } { $w.menu add command -label $d -command "$w configure -text $d" incr d } } #--------------------------------------------------------------------------- # ModifyDay -- bring up dialog for adding reminder. # Arguments: # d -- which day to modify # firstDay -- first weekday in month (0-6) #--------------------------------------------------------------------------- proc ModifyDay {d firstDay} { global ModifyDialogResult AppendFile HighestTagSoFar ReminderTags catch {destroy .mod} toplevel .mod CreateModifyDialog .mod $d $firstDay "Cancel" "Add to reminder file" "Preview reminder" wm title .mod "TkRemind Add Reminder..." wm iconname .mod "Add Reminder" tkwait visibility .mod set oldFocus [focus] while {1} { grab .mod focus .mod.entry set ModifyDialogResult -1 tkwait variable ModifyDialogResult if {$ModifyDialogResult == 1} { catch {focus $oldFocus} destroy .mod return 0 } set problem [catch {set rem [CreateReminder .mod]} err] if {$problem} { tk_dialog .error Error "$err" error 0 Ok } else { if {$ModifyDialogResult == 3} { set rem [EditReminder $rem Cancel "Add reminder"] if {$ModifyDialogResult == 1} { continue } } set opts [RemindDialogToOptions .mod] catch {focus $oldFocus} destroy .mod Status "Writing reminder..." set f [open $AppendFile a] incr HighestTagSoFar set ReminderTags($HighestTagSoFar) 1 WriteReminder $f TKTAG$HighestTagSoFar $rem $opts close $f FillCalWindow RestartBackgroundRemindDaemon return 0 } } } #--------------------------------------------------------------------------- # CenterWindow -- center a window on the screen. Stolen from tk_dialog code # Arguments: # w -- window to center #--------------------------------------------------------------------------- proc CenterWindow {w} { wm withdraw $w update idletasks set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \ - [winfo vrootx [winfo parent $w]]] set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \ - [winfo vrooty [winfo parent $w]]] wm geom $w +$x+$y wm deiconify $w } #--------------------------------------------------------------------------- # CreateReminder -- create the reminder # Arguments: # w -- the window containing the add reminder dialog box. # Returns: # The reminder as a string. #--------------------------------------------------------------------------- proc CreateReminder {w} { global DidOmit TwentyFourHourMode set body [string trim [$w.entry get]] if {"$body" == ""} { error "Blank body in reminder" } set DidOmit 0 set needOmit 0 # Delegate the first part to CreateReminder1, CreateReminder2, or # CreateReminder3 global OptionType SkipType repbut expbut advbut advcount global timebut timeadvbut timerepbut durationbut set rem [CreateReminder$OptionType $w] # Do the "until" part if {$expbut} { append rem " UNTIL [$w.expday cget -text] [$w.expmon cget -text] [$w.expyear cget -text]" } # Advance warning if {$advbut} { append rem " +" if {!$advcount} { append rem "+" } else { set needOmit 1 } append rem [$w.advdays cget -text] } # Timed reminder if {$timebut} { set hour [$w.timehour cget -text] set min [$w.timemin cget -text] if {!$TwentyFourHourMode} { if {[$w.ampm cget -text] == "PM"} { if {$hour < 12} { incr hour 12 } } else { if {$hour == 12} { set hour 0 } } } append rem " AT $hour:$min" if {$timeadvbut} { append rem " +[$w.timeadv cget -text]" } if {$timerepbut} { append rem " *[$w.timerep cget -text]" } if {$durationbut} { append rem " DURATION [$w.durationh cget -text]:[$w.durationm cget -text]" } } global SkipType if {$SkipType == 2} { append rem " SKIP" set needOmit 1 } elseif {$SkipType == 3} { append rem " BEFORE" set needOmit 1 } elseif {$SkipType == 4} { append rem " AFTER" set needOmit 1 } if {$needOmit && !$DidOmit} { append rem " OMIT [GetWeekend $w 1]" } # Check it out! global Remind set f [open "|$Remind -arq -e -" r+] puts $f "BANNER %" puts $f "$rem MSG %" puts $f "MSG %_%_%_%_" puts $f "FLUSH" flush $f set err {} catch {set err [gets $f]} catch {close $f} if {"$err" != ""} { # Clean up the message a bit regsub -- {^-stdin-\([0-9]*\): } $err {} err error "Error from Remind: $err" } append rem " MSG " [string map -nocase {"\n" " "} $body] return $rem } #--------------------------------------------------------------------------- # CreateReminder1 -- Create the first part of a type-1 reminder # Arguments: # w -- add reminder dialog window # Returns: first part of reminder #--------------------------------------------------------------------------- proc CreateReminder1 {w} { global repbut set rem "REM" set gotDay 0 set gotMon 0 set gotYear 0 set d [$w.day1 cget -text] if {"$d" != "every day"} { append rem " $d" set gotDay 1 } set m [$w.mon1 cget -text] if {"$m" != "every month"} { append rem " $m" set gotMon 1 } set y [$w.year1 cget -text] if {"$y" != "every year"} { append rem " $y" set gotYear 1 } # Check for repetition if {$repbut} { if {!$gotDay || !$gotMon || !$gotYear} { error "All components of a date must be specified if you wish to use the repeat feature." } append rem " *[$w.repdays cget -text]" } return $rem } #--------------------------------------------------------------------------- # CreateReminder2 -- Create the first part of a type-2 reminder # Arguments: # w -- add reminder dialog window # Returns: first part of reminder #--------------------------------------------------------------------------- proc CreateReminder2 {w} { set wkday [$w.wkday2 cget -text] if {"$wkday" == "weekday"} { set wkday [GetWeekend $w 0] } set day [$w.day2 cget -text] set mon [$w.mon2 cget -text] set year [$w.year2 cget -text] set rem "REM $wkday $day" if {$mon != "every month"} { append rem " $mon" } if {$year != "every year"} { append rem " $year" } return $rem } #--------------------------------------------------------------------------- # CreateReminder3 -- Create the first part of a type-3 reminder # Arguments: # w -- add reminder dialog window # Returns: first part of reminder #--------------------------------------------------------------------------- proc CreateReminder3 {w} { global MonthNames DidOmit set which [$w.ordinal cget -text] set day [$w.wkday3 cget -text] set mon [$w.mon3 cget -text] set year [$w.year3 cget -text] set rem "REM" if {$which != "Last"} { if {$which == "First"} { append rem " 1" } elseif {$which == "Second"} { append rem " 8" } elseif {$which == "Third"} { append rem " 15" } elseif {$which == "Fourth"} { append rem " 22" } if {$day != "weekday"} { append rem " $day" } else { append rem " [GetWeekend $w 0]" } if {$mon != "every month"} { append rem " $mon" } if {$year != "every year"} { append rem " $year" } } else { if {$day != "weekday"} { append rem " $day 1 --7" } else { append rem " 1 -1 OMIT [GetWeekend $w 1]" set DidOmit 1 } if {$mon != "every month"} { set i [lsearch -exact $MonthNames $mon] if {$i == 11} { set i 0 } else { incr i } append rem " [lindex $MonthNames $i]" } if {$year != "every year"} { if {$mon == "December"} { incr year } append rem " $year" } } return $rem } #--------------------------------------------------------------------------- # GetWeekend -- returns a list of weekdays or weekend days # Arguments: # w -- add reminder dialog window # wkend -- if 1, we want weekend. If 0, we want weekdays. # Returns: # list of weekdays or weekend-days #--------------------------------------------------------------------------- proc GetWeekend {w wkend} { global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday global EnglishDayNames set ret {} foreach d $EnglishDayNames { set v [set d$d] if {$v == $wkend} { lappend ret $d } } return $ret } #--------------------------------------------------------------------------- # EditReminder -- allow user to edit what gets put in reminder file # Arguments: # rem -- current reminder # args -- buttons to add to bottom # Returns: # edited version of rem #--------------------------------------------------------------------------- proc EditReminder {rem args} { catch {destroy .edit} global ModifyDialogResult toplevel .edit wm title .edit "TkRemind Preview reminder" wm iconname .edit "Preview reminder" text .edit.t -width 80 -height 5 -relief sunken .edit.t insert end $rem frame .edit.f set n 0 foreach but $args { incr n button .edit.but$n -text $but -command "set ModifyDialogResult $n" pack .edit.but$n -in .edit.f -side left -fill x -expand 1 } pack .edit.t -side top -fill both -expand 1 pack .edit.f -side top -fill x -expand 1 bind .edit ".edit.but1 flash; .edit.but1 invoke" set ModifyDialogResult 0 CenterWindow .edit tkwait visibility .edit set oldFocus [focus] focus .edit.t grab .edit tkwait variable ModifyDialogResult catch {focus $oldFocus} set rem [.edit.t get 1.0 end] catch {destroy .edit} return $rem } #--------------------------------------------------------------------------- # SetWinAttr -- sets an attribute for a window # Arguments: # w -- window name # attr -- attribute name # val -- value to set it to # Returns: # $val #--------------------------------------------------------------------------- proc SetWinAttr {w attr val} { global attrPriv set attrPriv($w-$attr) $val } #--------------------------------------------------------------------------- # GetWinAttr -- gets an attribute for a window # Arguments: # w -- window name # attr -- attribute name # Returns: # Value of attribute #--------------------------------------------------------------------------- proc GetWinAttr {w attr} { global attrPriv return $attrPriv($w-$attr) } #--------------------------------------------------------------------------- # WaitWinAttr -- wait for a window attribute to change # Arguments: # w -- window name # attr -- attribute name # Returns: # Value of attribute #--------------------------------------------------------------------------- proc WaitWinAttr {w attr} { global attrPriv tkwait variable attrPriv($w-$attr) return $attrPriv($w-$attr) } #--------------------------------------------------------------------------- # BrowseForFile -- creates and operates a file browser dialog. # Arguments: # w -- dialog window. # title -- dialog title # oktext -- text for "OK" button # showdots -- if non-zero, shows "dot" files as well. # Returns: # complete path of filename chosen, or "" if Cancel pressed. #--------------------------------------------------------------------------- proc BrowseForFile {w title {oktext "OK"} {showdots 0} {filter "*"}} { catch {destroy $w} toplevel $w wm title $w $title # Global array to hold window attributes global a${w} SetWinAttr $w status busy SetWinAttr $w showdots $showdots frame $w.fileframe frame $w.butframe label $w.cwd -text [pwd] entry $w.entry label $w.masklab -text "Match: " listbox $w.list -yscrollcommand "$w.scroll set" scrollbar $w.scroll -command "$w.list yview" button $w.ok -text $oktext -command "BrowseForFileOK $w" button $w.cancel -text "Cancel" -command "BrowseForFileCancel $w" entry $w.filter -width 7 $w.filter insert end $filter pack $w.cwd $w.entry -side top -expand 0 -fill x pack $w.fileframe -side top -expand 1 -fill both pack $w.butframe -side top -expand 0 -fill x pack $w.list -in $w.fileframe -side left -expand 1 -fill both pack $w.scroll -in $w.fileframe -side left -expand 0 -fill y pack $w.ok -in $w.butframe -side left -expand 1 -fill x pack $w.cancel -in $w.butframe -side left -expand 1 -fill x pack $w.masklab -in $w.butframe -side left -expand 0 pack $w.filter -in $w.butframe -side left -expand 1 -fill x # Fill in the box and wait for status to change BrowseForFileRead $w [pwd] bind $w "$w.cancel flash; $w.cancel invoke" bind $w.list "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]" bind $w.list "$w.ok flash; $w.ok invoke" bind $w.list "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]; $w.ok flash; $w.ok invoke" bind $w.entry "$w.ok flash; $w.ok invoke" bind $w.filter "BrowseForFileRead $w" bind $w.entry "CompleteFile $w" bind $w.entry "ExpandFile $w" bindtags $w.entry "Entry $w.entry $w all" bindtags $w.list "Listbox $w.list $w all" CenterWindow $w set oldFocus [focus] tkwait visibility $w focus $w.entry set oldGrab [grab current $w] grab set $w WaitWinAttr $w status catch {focus $oldFocus} catch {grab set $oldGrab} set ans [GetWinAttr $w status] destroy $w return $ans } proc CompleteFile {w} { set index [lsearch [$w.list get 0 end] [$w.entry get]* ] if {$index > -1} { $w.list see $index $w.list selection clear 0 end $w.list selection set $index } } proc ExpandFile {w} { set stuff [$w.list curselection] if {[string compare $stuff ""]} { $w.entry delete 0 end $w.entry insert end [$w.list get $stuff] } } proc BrowseForFileCancel {w} { SetWinAttr $w status {} } proc BrowseForFileOK {w} { set fname [$w.entry get] if {[string compare $fname ""]} { # If it starts with a slash, handle it specially. if {[string match "/*" $fname]} { if {[file isdirectory $fname]} { BrowseForFileRead $w $fname return } else { SetWinAttr $w status $fname return } } if {[string match */ $fname]} { set fname [string trimright $fname /] } if {[$w.cwd cget -text] == "/"} { set fname "/$fname" } else { set fname "[$w.cwd cget -text]/$fname" } # If it's a directory, change directories if {[file isdirectory $fname]} { BrowseForFileRead $w $fname } else { SetWinAttr $w status $fname } } } #--------------------------------------------------------------------------- # BrowseForFileRead -- read the current directory into the file browser # Arguments: # w -- window name # dir -- directory # Returns: # nothing #--------------------------------------------------------------------------- proc BrowseForFileRead {w {dir ""}} { # Save working dir set cwd [pwd] if {$dir == ""} { set dir [$w.cwd cget -text] } if {[catch "cd $dir" err]} { tk_dialog .error Error "$err" error 0 Ok return } $w.cwd configure -text [pwd] if {[GetWinAttr $w showdots]} { set flist [glob -nocomplain .* *] } else { set flist [glob -nocomplain *] } set flist [lsort $flist] set filter [$w.filter get] if {$filter == ""} { set filter "*" } $w.list delete 0 end foreach item $flist { if {$item != "." && $item != ".."} { if {[file isdirectory $item]} { $w.list insert end "$item/" } else { if {[string match $filter $item]} { $w.list insert end $item } } } } if {[pwd] != "/"} { $w.list insert 0 "../" } cd $cwd $w.entry delete 0 end } #--------------------------------------------------------------------------- # StartBackgroundRemindDaemon # Arguments: # none # Returns: # nothing # Description: # Starts a background Remind daemon to handle timed reminders #--------------------------------------------------------------------------- proc StartBackgroundRemindDaemon {} { global Remind DaemonFile ReminderFile set problem [catch { set DaemonFile [open "|$Remind -z0 $ReminderFile" "r+"] } err] if {$problem} { tk_dialog .error Error "Can't start Remind daemon in background: $err" error 0 OK } else { fileevent $DaemonFile readable "DaemonReadable $DaemonFile" puts $DaemonFile "STATUS" flush $DaemonFile } } #--------------------------------------------------------------------------- # StopBackgroundRemindDaemon # Arguments: # none # Returns: # nothing # Description: # Stops the background Remind daemon #--------------------------------------------------------------------------- proc StopBackgroundRemindDaemon {} { global DaemonFile catch { puts $DaemonFile "EXIT" flush $DaemonFile close $DaemonFile } } #--------------------------------------------------------------------------- # RestartBackgroundRemindDaemon # Arguments: # none # Returns: # nothing # Description: # Restarts the background Remind daemon #--------------------------------------------------------------------------- proc RestartBackgroundRemindDaemon {} { global DaemonFile catch { puts $DaemonFile "REREAD" flush $DaemonFile } } #--------------------------------------------------------------------------- # DaemonReadable # Arguments: # file -- file channel that is readable # Returns: # nothing # Description: # Reads data from the Remind daemon and handles it appropriately #--------------------------------------------------------------------------- proc DaemonReadable { file } { global Ignore set line "" catch { set num [gets $file line] } if {$num < 0} { catch { close $file } return } switch -glob -- $line { "NOTE reminder*" { scan $line "NOTE reminder %s %s %s" time now tag IssueBackgroundReminder $file $time $now $tag } "NOTE newdate" { # Date has rolled over -- clear "ignore" list catch { unset Ignore} Initialize FillCalWindow ShowTodaysReminders } "NOTE reread" { puts $file "STATUS" flush $file } "NOTE queued*" { scan $line "NOTE queued %d" n if {$n == 1} { .b.nqueued configure -text "1 reminder queued" } else { .b.nqueued configure -text "$n reminders queued" } } default { puts "Unknown message from daemon: $line\n" } } } #--------------------------------------------------------------------------- # IssueBackgroundReminder # Arguments: # file -- file channel that is readable # time -- time of reminder # now -- current time according to Remind daemon # tag -- tag for reminder, or "*" if no tag # Returns: # nothing # Description: # Reads a background reminder from daemon and pops up window. #--------------------------------------------------------------------------- proc IssueBackgroundReminder { file time now tag } { global BgCounter Option Ignore if {$Option(Deiconify)} { wm deiconify . } set msg "" set line "" while (1) { gets $file line if {$line == "NOTE endreminder"} { break } if {$msg != ""} { append msg "\n"; } append msg $line } # Do nothing if it's blank -- was probably a RUN-type reminder. if {$msg == ""} { return } # Do nothing if user told us to ignore this reminder if {[info exists Ignore($tag)]} { return } incr BgCounter set w .bg$BgCounter toplevel $w wm iconname $w "Reminder" wm title $w "Timed reminder ($time)" label $w.l -text "Reminder for $time issued at $now" message $w.msg -width 6i -text $msg frame $w.b # Automatically shut down window after a minute if option says so set after_token [after 60000 [list ClosePopup $w "" $Option(MailAddr) $Option(AutoClose) "" $tag $msg $time]] wm protocol $w WM_DELETE_WINDOW [list ClosePopup $w $after_token "" 1 "" $tag $msg $time] button $w.ok -text "OK" -command [list ClosePopup $w $after_token "" 1 "" $tag $msg $time] if {$tag != "*"} { button $w.nomore -text "Don't remind me again today" -command [list ClosePopup $w $after_token "" 1 "ignore" $tag $msg $time] button $w.kill -text "Delete this reminder completely" -command [list ClosePopup $w $after_token "" 1 "kill" $tag $msg $time] } pack $w.l -side top pack $w.msg -side top -expand 1 -fill both pack $w.b -side top pack $w.ok -in $w.b -side left if {$tag != "*"} { pack $w.nomore $w.kill -in $w.b -side left } CenterWindow $w update if {$Option(RingBell)} { bell } if {$Option(RunCmd) != ""} { if {$Option(FeedReminder)} { FeedReminderToCommand $Option(RunCmd) $msg } else { exec "/bin/sh" "-c" $Option(RunCmd) "&" } } # reread status if {$file != "stdin"} { puts $file "STATUS" flush $file } } #*********************************************************************** # %PROCEDURE: FeedReminderToCommand # %ARGUMENTS: # cmd -- command to execute # msg -- what to feed it # %RETURNS: # Nothing # %DESCRIPTION: # Feeds "$msg" to a command. #*********************************************************************** proc FeedReminderToCommand { cmd msg } { catch { set f [open "|$cmd" "w"] fconfigure $f -blocking 0 fileevent $f writable [list CommandWritable $f $msg] } } #*********************************************************************** # %PROCEDURE: CommandWritable # %ARGUMENTS: # f -- file which is writable # msg -- message to write # %RETURNS: # Nothing # %DESCRIPTION: # Writes $msg to $f; closes $f. #*********************************************************************** proc CommandWritable { f msg } { puts $f $msg flush $f close $f } proc main {} { # If no ~/.tkremindrc file, create an empty one if {![file exists ~/.tkremindrc]} { catch { set f [open ~/.tkremindrc "w"] close $f } } global AppendFile HighestTagSoFar DayNames catch { puts "\nTkRemind Copyright (C) 1996-1998 Dianne Skoll" puts "Copyright (C) 1999-2010 Roaring Penguin Software Inc." } catch { SetFonts } LoadOptions CreateMoonImages Initialize ShowTodaysReminders ScanForTags $AppendFile CreateCalWindow $DayNames FillCalWindow StartBackgroundRemindDaemon DisplayTimeContinuously } #*********************************************************************** # %PROCEDURE: ScanForTags # %ARGUMENTS: # fname -- name of file to scan # %RETURNS: # Nothing # %DESCRIPTION: # Scans the file for all tags of the form "TKTAGnnnn" and builds # the tag array. Also adjusts HighestTagSoFar #*********************************************************************** proc ScanForTags { fname } { global HighestTagSoFar ReminderTags if {[catch { set f [open $fname "r"]}]} { return } while {[gets $f line] >= 0} { switch -regexp -- $line { {^# TKTAG[0-9]+} { regexp {^# TKTAG([0-9]+)} $line dummy tagno if {$tagno > $HighestTagSoFar} { set HighestTagSoFar $tagno } set ReminderTags($tagno) 1 } } } close $f } #*********************************************************************** # %PROCEDURE: ReadTaggedOptions # %ARGUMENTS: # tag -- tag to match # %RETURNS: # A list of options for the dialog box for the tagged reminder # %DESCRIPTION: # Scans the file for specified tag and returns the "options" list for the # reminder. #*********************************************************************** proc ReadTaggedOptions { tag } { global AppendFile if {[catch { set f [open $AppendFile "r"]}]} { return "" } while {[gets $f line] >= 0} { if {[string match "# $tag *" $line]} { gets $f line close $f return [string range $line 2 end] } } close $f return "" } proc FireEditor { w } { global Option global EditorPid set tags [$w tag names current] set index [lsearch -glob $tags "FILE_*"] if {$index < 0} { return } set tag [lindex $tags $index] if {![regexp {^FILE_([0-9]+)_(.*)} $tag all line file]} { return } set editor $Option(Editor) regsub -all "%s" $editor $file editor regsub -all "%d" $editor $line editor # Don't fire up a second editor if first is running if {$EditorPid >= 0} { if {![catch {exec kill -0 $EditorPid}]} { Status "Editor already active!" after 2500 DisplayTime bell return } } Status "Firing up editor..." after 1500 DisplayTime set EditorPid [exec sh -c $editor &] } #*********************************************************************** # %PROCEDURE: GetCurrentReminder # %ARGUMENTS: # w -- text window # %RETURNS: # The tag (TKTAGnnnn) for current editable reminder, or "" if no # current editable reminder. #*********************************************************************** proc GetCurrentReminder { w } { set tags [$w tag names current] set index [lsearch -glob $tags "TKTAG*"] if {$index < 0} { return "" } set tag [lindex $tags $index] return $tag } #*********************************************************************** # %PROCEDURE: TaggedEnter # %ARGUMENTS: # w -- text window # %RETURNS: # Nothing # %DESCRIPTION: # Highlights an "editable" reminder as mouse moves into it #*********************************************************************** proc TaggedEnter { w } { set tag [GetCurrentReminder $w] if {$tag != ""} { $w tag configure $tag -foreground #FF0000 } } #*********************************************************************** # %PROCEDURE: TaggedLeave # %ARGUMENTS: # w -- text window # %RETURNS: # Nothing # %DESCRIPTION: # Removes highlight from an "editable" reminder as mouse leaves it #*********************************************************************** proc TaggedLeave { w } { set tag [GetCurrentReminder $w] if {$tag != ""} { set tags [$w tag names current] set index [lsearch -glob $tags "clr*"] if {$index < 0} { set fg "#000000" } else { set fg [string range [lindex $tags $index] 3 end] set fg "#$fg" } $w tag configure $tag -foreground $fg } } #*********************************************************************** # %PROCEDURE: EditTaggedReminder # %ARGUMENTS: # w -- text window # %RETURNS: # Nothing # %DESCRIPTION: # Opens a dialog box to edit the current editable reminder #*********************************************************************** proc EditTaggedReminder { w } { global ModifyDialogResult set tag [GetCurrentReminder $w] if {$tag == ""} { return } # Read in options set opts [ReadTaggedOptions $tag] if {$opts == ""} { return } toplevel .mod CreateModifyDialog .mod 1 0 "Cancel" "Replace reminder" "Delete reminder" "Preview reminder" wm title .mod "TkRemind Edit Reminder..." wm iconname .mod "Edit Reminder" OptionsToRemindDialog .mod $opts tkwait visibility .mod set oldFocus [focus] while {1} { grab .mod focus .mod.entry set ModifyDialogResult -1 tkwait variable ModifyDialogResult if {$ModifyDialogResult == 1} { catch {focus $oldFocus} destroy .mod return 0 } set problem [catch {set rem [CreateReminder .mod]} err] if {$problem} { tk_dialog .error Error "$err" error 0 Ok continue } if {$ModifyDialogResult == 4} { set rem [EditReminder $rem "Cancel" "Replace reminder"] if {$ModifyDialogResult == 1} { continue } } set opts [RemindDialogToOptions .mod] catch {focus $oldFocus} destroy .mod set problem [catch { if {$ModifyDialogResult == 2} { ReplaceTaggedReminder $tag $rem $opts } else { DeleteTaggedReminder $tag } } err] if {$problem} { tk_dialog .error Error "Error: $err" error 0 Ok return 1 } FillCalWindow RestartBackgroundRemindDaemon return 0 } } #*********************************************************************** # %PROCEDURE: UniqueFileName # %ARGUMENTS: # stem -- base name of file # %RETURNS: # A filename of the form "stem.xxx" which does not exist #*********************************************************************** proc UniqueFileName { stem } { set n 1 while {[file exists $stem.$n]} { incr n } return $stem.$n } #*********************************************************************** # %PROCEDURE: DeleteTaggedReminder # %ARGUMENTS: # tag -- tag of reminder to delete # %RETURNS: # Nothing # %DESCRIPTION: # Deletes tagged reminder from reminder file #*********************************************************************** proc DeleteTaggedReminder { tag } { global AppendFile set tmpfile [UniqueFileName $AppendFile] set out [open $tmpfile "w"] set in [open $AppendFile "r"] set foundStart 0 set foundEnd 0 while {[gets $in line] >= 0} { if {[string match "# $tag *" $line]} { set foundStart 1 break } puts $out $line } if {! $foundStart} { close $in close $out file delete $tmpfile error "Did not find start of reminder with tag $tag" } while {[gets $in line] >= 0} { if { $line == "# TKEND"} { set foundEnd 1 break } } if {! $foundEnd} { close $in close $out file delete $tmpfile error "Did not find end of reminder with tag $tag" } while {[gets $in line] >= 0} { puts $out $line } close $in close $out file rename -force -- $tmpfile $AppendFile } #*********************************************************************** # %PROCEDURE: ReplaceTaggedReminder # %ARGUMENTS: # tag -- tag of reminder to replace # rem -- text to replace it with # opts -- edit options # %RETURNS: # Nothing # %DESCRIPTION: # Replaces a tagged reminder in the reminder file #*********************************************************************** proc ReplaceTaggedReminder { tag rem opts } { global AppendFile set tmpfile [UniqueFileName $AppendFile] set out [open $tmpfile "w"] set in [open $AppendFile "r"] set foundStart 0 set foundEnd 0 while {[gets $in line] >= 0} { if {[string match "# $tag *" $line]} { set foundStart 1 break } puts $out $line } if {! $foundStart} { close $in close $out file delete $tmpfile error "Did not find start of reminder with tag $tag" } # Consume the old reminder while {[gets $in line] >= 0} { if { $line == "# TKEND"} { set foundEnd 1 break } } if {! $foundEnd} { close $in close $out file delete $tmpfile error "Did not find end of reminder with tag $tag" } # Write the new reminder WriteReminder $out $tag $rem $opts # Copy rest of file over while {[gets $in line] >= 0} { puts $out $line } close $in close $out file rename -force -- $tmpfile $AppendFile } #*********************************************************************** # %PROCEDURE: WriteReminder # %ARGUMENTS: # out -- file to write to # tag -- reminder tag # rem -- reminder body # opts -- edit options # %RETURNS: # Nothing # %DESCRIPTION: # Writes a reminder to a file #*********************************************************************** proc WriteReminder { out tag rem opts } { puts $out "# $tag Next reminder was created with TkRemind. DO NOT EDIT" puts $out "# $opts" if {[string range $rem 0 3] == "REM "} { puts $out "REM TAG $tag [string range $rem 4 end]" } else { puts $out $rem } puts $out "# TKEND" } #*********************************************************************** # %PROCEDURE: DoShadeSpecial # %ARGUMENTS: # n -- calendar box to shade # stuff -- Remind command line # %RETURNS: # Nothing # %DESCRIPTION: # Handles the "SHADE" special -- shades a box. #*********************************************************************** proc DoShadeSpecial { n stuff } { set num [scan $stuff "%d %d %d" r g b] if {$num == 1} { set g $r set b $r } elseif {$num != 3} { return } if {$r < 0 || $r > 255 || $g < 0 || $g > 255 || $b < 0 || $b > 255} { return } set bg [format "#%02x%02x%02x" $r $g $b] .cal.t$n configure -background $bg } #*********************************************************************** # %PROCEDURE: DoMoonSpecial # %ARGUMENTS: # n -- calendar box for moon # stuff -- Remind command line # %RETURNS: # Nothing # %DESCRIPTION: # Handles the "MOON" special -- draws a moon symbol #*********************************************************************** proc DoMoonSpecial { n stuff } { set msg "" set num [scan $stuff "%d %d %d %s" phase junk1 junk2 msg] if {$num < 1} { return } if {$phase < 0 || $phase > 3} { return } switch -exact -- $phase { 0 { set image new } 1 { set image first } 2 { set image full } 3 { set image last } } .cal.t$n configure -state normal .cal.t$n image create 1.0 -image $image if {$msg != ""} { .cal.t$n insert 1.1 " $msg\n" } else { .cal.t$n insert 1.1 "\n" } .cal.t$n configure -state disabled } #*********************************************************************** # %PROCEDURE: DisplayTime # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Displays current date and time in status window #*********************************************************************** proc DisplayTime {} { global TwentyFourHourMode if {$TwentyFourHourMode} { set msg [clock format [clock seconds] -format "%e %b %Y %H:%M"] } else { set msg [clock format [clock seconds] -format "%e %b %Y %I:%M%p"] } Status $msg } #*********************************************************************** # %PROCEDURE: CreateMoonImages # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Creates the moon images "new", "first", "full" and "last" #*********************************************************************** proc CreateMoonImages {} { image create bitmap full -foreground black \ -data "#define newmoon_width 16\n#define newmoon_height 16\nstatic unsigned char newmoon_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0x04, 0x10, 0x02, 0x20,\n0x02, 0x20, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x02, 0x20, 0x02, 0x20,\n0x04, 0x10, 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01};" image create bitmap first -foreground black \ -data "#define firstquarter_width 16\n#define firstquarter_height 16\nstatic unsigned char firstquarter_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0xf0, 0x06, 0xfc, 0x18, 0xfc, 0x10, 0xfe, 0x20,\n0xfe, 0x20, 0xff, 0x40, 0xff, 0x40, 0xff, 0x40, 0xfe, 0x20, 0xfe, 0x20,\n0xfc, 0x10, 0xfc, 0x18, 0xf0, 0x06, 0xc0, 0x01};" image create bitmap new -foreground black \ -data "#define fullmoon_width 16\n#define fullmoon_height 16\nstatic unsigned char fullmoon_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0xf0, 0x07, 0xfc, 0x1f, 0xfc, 0x1f, 0xfe, 0x3f,\n0xfe, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x3f, 0xfe, 0x3f,\n0xfc, 0x1f, 0xfc, 0x1f, 0xf0, 0x07, 0xc0, 0x01};" image create bitmap last -foreground black \ -data "#define lastquarter_width 16\n#define lastquarter_height 16\nstatic unsigned char lastquarter_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0xb0, 0x07, 0x8c, 0x1f, 0x84, 0x1f, 0x82, 0x3f,\n0x82, 0x3f, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x82, 0x3f, 0x82, 0x3f,\n0x84, 0x1f, 0x8c, 0x1f, 0xb0, 0x07, 0xc0, 0x01};" } #*********************************************************************** # %PROCEDURE: DisplayTimeContinuously # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Continuously displays current date and time in status window, # updating once a minute #*********************************************************************** proc DisplayTimeContinuously {} { DisplayTime set secs [clock format [clock seconds] -format "%S"] # Doh -- don't interpret as an octal number if leading zero scan $secs "%d" decSecs set decSecs [expr 60 - $decSecs] after [expr $decSecs * 1000] DisplayTimeContinuously } #*********************************************************************** # %PROCEDURE: ShowTodaysReminders # %ARGUMENTS: # None # %RETURNS: # Nothing # %DESCRIPTION: # Shows all of today's non-timed reminders in a window #*********************************************************************** proc ShowTodaysReminders {} { global Option global Remind global ReminderFile if {!$Option(ShowTodaysReminders)} { return } set w .today catch { destroy $w } toplevel $w wm title $w "Today's Reminders" wm iconname $w "Reminders" text $w.text -width 80 -height 20 -wrap word -yscrollcommand "$w.sb set" scrollbar $w.sb -orient vertical -command "$w.text yview" button $w.ok -text "OK" -command "destroy $w" grid $w.text -row 0 -column 0 -sticky nsew grid $w.sb -row 0 -column 1 -sticky ns grid $w.ok -row 1 -column 0 -sticky w CenterWindow $w # Grab the reminders set stuff [exec -keepnewline $Remind -g -q -r $ReminderFile 2>/dev/null] $w.text insert end $stuff $w.text configure -state disabled } #*********************************************************************** # %PROCEDURE: InteractiveDeleteReminder # %ARGUMENTS: # tag -- tag of reminder to delete # %RETURNS: # Nothing # %DESCRIPTION: # Prompts for confirmation; then deletes reminder #*********************************************************************** proc InteractiveDeleteReminder { tag } { set ans [tk_dialog .error "Really Delete" "Really delete reminder?" warning 0 No Yes] if {$ans == 1} { DeleteTaggedReminder $tag FillCalWindow RestartBackgroundRemindDaemon } } proc SendMail { recipient subject body } { global Option if {"$Option(MailAddr)" == ""} { return } if {[catch {set token [mime::initialize -canonical text/plain -string $body] mime::setheader $token Subject $subject mime::setheader $token From "Reminder Service <>" mime::setheader $token To "<$recipient>" mime::setheader $token Auto-Submitted "auto-generated" smtp::sendmessage $token -originator "" -servers $Option(SMTPServer) -recipients $Option(MailAddr)} err]} { puts stderr "ERROR sending mail: $err" } } proc ClosePopup { w after_token mail_addr close_win ignore_or_kill tag reminder rem_time } { global Ignore if {"$after_token" != ""} { catch { after cancel $after_token } } if {$close_win} { catch { destroy $w } } if {"$mail_addr" != ""} { SendMail $mail_addr "Reminder for $rem_time" "Hello,\n\nThe following reminder is scheduled for $rem_time:\n\n$reminder\nRegards,\n\nTkRemind\n" } if {"$ignore_or_kill" == "ignore"} { set Ignore($tag) 1 } if {"$ignore_or_kill" == "kill"} { InteractiveDeleteReminder $tag } } # Adjust font defaults for screen size proc SetFonts {} { global SetFontsWorked set h [winfo screenheight .] if {$h <= 480} { # Small screen (maybe eeepc?) font configure TkDefaultFont -size 6 font configure TkFixedFont -size 6 } set SetFontsWorked 1 } main remind-03.01.15/src/Makefile.in0000644000076400007640000000516612040002210014162 0ustar dfsdfs# Makefile.in for REMIND # SHELL= /bin/sh BETA = 1 srcdir=@srcdir@ prefix=@prefix@ exec_prefix=@exec_prefix@ mandir=@mandir@ bindir=@bindir@ datadir=@datadir@ datarootdir=@datarootdir@ VPATH=$(srcdir) VERSION=@VERSION@ INSTALL=@INSTALL@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ INSTALL_DATA=@INSTALL_DATA@ PROGS= remind rem2ps SCRIPTS= $(srcdir)/../scripts/tkremind $(srcdir)/../scripts/cm2rem.tcl MANS= $(srcdir)/../man/rem2ps.1 $(srcdir)/../man/remind.1 \ $(srcdir)/../man/tkremind.1 $(srcdir)/../man/cm2rem.1 \ $(srcdir)/../man/rem.1 .SUFFIXES: .SUFFIXES: .c .o REMINDSRCS= calendar.c dynbuf.c dorem.c dosubst.c expr.c files.c funcs.c \ globals.c hbcal.c init.c main.c md5.c moon.c omit.c queue.c \ sort.c token.c trigger.c userfns.c utils.c var.c REMINDHDRS=config.h custom.h dynbuf.h err.h expr.h globals.h lang.h \ md5.h protos.h rem2ps.h types.h version.h REMINDOBJS= $(REMINDSRCS:.c=.o) all: remind rem2ps test: remind @sh ../tests/test-rem .c.o: @CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) $(LANGDEF) -I. -I$(srcdir) $< rem2ps: rem2ps.o dynbuf.o @CC@ @LDFLAGS@ $(LDEXTRA) -o rem2ps rem2ps.o dynbuf.o remind: $(REMINDOBJS) @CC@ @LDFLAGS@ $(LDEXTRA) -o remind $(REMINDOBJS) @LIBS@ install-nostripped: all -mkdir -p $(DESTDIR)$(bindir) || true for prog in $(PROGS) $(SCRIPTS) ; do \ $(INSTALL_PROGRAM) $$prog $(DESTDIR)$(bindir) || exit 1; \ done rm -f $(DESTDIR)$(bindir)/rem > /dev/null 2>&1 || true ln -s remind $(DESTDIR)$(bindir)/rem -mkdir -p $(DESTDIR)$(mandir)/man1 || true for man in $(MANS) ; do \ $(INSTALL_DATA) $$man $(DESTDIR)$(mandir)/man1 || exit 1; \ done install: install-nostripped strip $(DESTDIR)$(bindir)/remind || true strip $(DESTDIR)$(bindir)/rem2ps || true clean: rm -f *.o *~ core *.bak $(PROGS) clobber: rm -f *.o *~ remind rem2ps test.out core *.bak depend: gccmakedep @DEFS@ $(REMINDSRCS) rem2ps.c # The next targets are not very useful to you. I use them to build # distributions, etc. # Build a tar file based on all files checked into git. distro: ln -s . ../remind-$(VERSION) (cd ..; git ls-files | fgrep -v .gitignore | fgrep -v remind.php) | sed -e 's/^/remind-$(VERSION)\//' | xargs tar -C .. -cvf remind-$(VERSION).tar gzip -f -v -9 remind-$(VERSION).tar rm -f ../remind-$(VERSION) beta-tgz: ln -s . ../remind-$(VERSION)-BETA-$(BETA) (cd ..; git ls-files | fgrep -v .gitignore | fgrep -v remind.php) | sed -e 's/^/remind-$(VERSION)-BETA-$(BETA)\//' | xargs tar -C .. -cvf remind-$(VERSION)-BETA-$(BETA).tar gzip -f -v -9 remind-$(VERSION)-BETA-$(BETA).tar rm -f ../remind-$(VERSION)-BETA-$(BETA) #---------------- Stuff after this added by "make depend" ----------------- remind-03.01.15/src/calendar.c0000644000076400007640000011320212514120776014051 0ustar dfsdfs/***************************************************************/ /* */ /* CALENDAR.C */ /* */ /* The code for generating a calendar. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #ifdef REM_USE_WCHAR #include #endif #include "types.h" #include "protos.h" #include "expr.h" #include "globals.h" #include "err.h" #include "md5.h" /* Data structures used by the calendar */ typedef struct cal_entry { struct cal_entry *next; char const *text; char const *pos; #ifdef REM_USE_WCHAR wchar_t const *wc_text; wchar_t const *wc_pos; #endif int is_color; int r, g, b; int time; int priority; DynamicBuffer tags; char passthru[PASSTHRU_LEN+1]; int duration; char const *filename; int lineno; } CalEntry; /* Line-drawing sequences */ struct line_drawing { char const *graphics_on; char const *graphics_off; char *tlr, *bl, *tbl, *blr, *tblr, *tr, *tb, *br, *tbr, *tl, *lr; }; static struct line_drawing NormalDrawing = { "", "", "+", "+", "+", "+", "+", "+", "|", "+", "+", "+", "-" }; static struct line_drawing VT100Drawing = { "\x1B(0", "\x1B(B", "\x76", "\x6b", "\x75", "\x77", "\x6e", "\x6d", "\x78", "\x6c", "\x74", "\x6a", "\x71" }; static struct line_drawing UTF8Drawing = { "", "", "\xe2\x94\xb4", "\xe2\x94\x90", "\xe2\x94\xa4", "\xe2\x94\xac", "\xe2\x94\xbc", "\xe2\x94\x94", "\xe2\x94\x82", "\xe2\x94\x8c", "\xe2\x94\x9c", "\xe2\x94\x98", "\xe2\x94\x80" }; static char *VT100Colors[2][2][2][2] /* [Br][R][G][B] */ = { { /*** DIM COLORS ***/ { { /* 0, 0, 0 = Black */ "\x1B[0;30m", /* 0, 0, 1 = Blue */ "\x1B[0;34m" }, { /* 0, 1, 0 = Green */ "\x1B[0;32m", /* 0, 1, 1 = Cyan */ "\x1B[0;36m" } }, { { /* 1, 0, 0 = Red */ "\x1B[0;31m", /* 1, 0, 1 = Magenta */ "\x1B[0;35m" }, { /* 1, 1, 0 = Yellow */ "\x1B[0;33m", /* 1, 1, 1 = White */ "\x1B[0;37m" } } }, { /*** BRIGHT COLORS ***/ { { /* 0, 0, 0 = Grey */ "\x1B[30;1m", /* 0, 0, 1 = Blue */ "\x1B[34;1m" }, { /* 0, 1, 0 = Green */ "\x1B[32;1m", /* 0, 1, 1 = Cyan */ "\x1B[36;1m" } }, { { /* 1, 0, 0 = Red */ "\x1B[31;1m", /* 1, 0, 1 = Magenta */ "\x1B[35;1m" }, { /* 1, 1, 0 = Yellow */ "\x1B[33;1m", /* 1, 1, 1 = White */ "\x1B[37;1m" } } } }; static struct line_drawing *linestruct; #define DRAW(x) fputs(linestruct->x, stdout) /* Global variables */ static CalEntry *CalColumn[7]; static int ColSpaces; static void Colorize(CalEntry const *e); static void Decolorize(void); static void SortCol (CalEntry **col); static void DoCalendarOneWeek (int nleft); static void DoCalendarOneMonth (void); static int WriteCalendarRow (void); static void WriteWeekHeaderLine (void); static void WritePostHeaderLine (void); static void PrintLeft (char const *s, int width, char pad); static void PrintCentered (char const *s, int width, char *pad); static int WriteOneCalLine (void); static int WriteOneColLine (int col); static void GenerateCalEntries (int col); static void WriteCalHeader (void); static void WriteCalTrailer (void); static int DoCalRem (ParsePtr p, int col); static void WriteSimpleEntries (int col, int jul); static void WriteTopCalLine (void); static void WriteBottomCalLine (void); static void WriteIntermediateCalLine (void); static void WriteCalDays (void); #ifdef REM_USE_WCHAR static void PutWideChar(wchar_t const wc) { char buf[MB_CUR_MAX+1]; int len; len = wctomb(buf, wc); if (len > 0) { buf[len] = 0; fputs(buf, stdout); } } #endif static int make_wchar_versions(CalEntry *e) { #ifdef REM_USE_WCHAR size_t len; wchar_t *buf; len = mbstowcs(NULL, e->text, 0); if (len == (size_t) -1) return 0; buf = calloc(len+1, sizeof(wchar_t)); if (!buf) return 0; (void) mbstowcs(buf, e->text, len+1); e->wc_text = buf; e->wc_pos = buf; return 1; #else return 1; #endif } static void gon(void) { printf("%s", linestruct->graphics_on); } static void goff(void) { printf("%s", linestruct->graphics_off); } static void Decolorize(void) { printf("%s", "\x1B[0m"); } static void Colorize(CalEntry const *e) { int bright = 0; int r, g, b; if (e->r > 128 || e->g > 128 || e->b > 128) { bright = 1; } if (e->r > 64) r = 1; else r = 0; if (e->g > 64) g = 1; else g = 0; if (e->b > 64) b = 1; else b = 0; printf("%s", VT100Colors[bright][r][g][b]); } /***************************************************************/ /* */ /* ProduceCalendar */ /* */ /* Main loop for generating a calendar. */ /* */ /***************************************************************/ void ProduceCalendar(void) { int y, m, d; if (UseUTF8Chars) { linestruct = &UTF8Drawing; } else if (UseVTChars) { linestruct = &VT100Drawing; } else { linestruct = &NormalDrawing; } ShouldCache = 1; ColSpaces = (CalWidth - 9) / 7; CalWidth = 7*ColSpaces + 8; if (CalMonths) { FromJulian(JulianToday, &y, &m, &d); JulianToday = Julian(y, m, 1); while (CalMonths--) DoCalendarOneMonth(); return; } else { if (MondayFirst) JulianToday -= (JulianToday%7); else JulianToday -= ((JulianToday+1)%7); if (!DoSimpleCalendar) { WriteWeekHeaderLine(); WriteCalDays(); WriteIntermediateCalLine(); } while (CalWeeks--) DoCalendarOneWeek(CalWeeks); return; } } /***************************************************************/ /* */ /* DoCalendarOneWeek */ /* */ /* Write a calendar for a single week */ /* */ /***************************************************************/ static void DoCalendarOneWeek(nleft) { int y, m, d, done, i, l, wd; char buf[81]; int LinesWritten = 0; int OrigJul = JulianToday; /* Fill in the column entries */ for (i=0; i<7; i++) { GenerateCalEntries(i); JulianToday++; } /* Output the entries */ /* If it's "Simple Calendar" format, do it simply... */ if (DoSimpleCalendar) { if (MondayFirst) wd = JulianToday % 7; else wd = (JulianToday + 1) % 7; for (i=0; i<7; i++) { WriteSimpleEntries(i, OrigJul+i-wd); } return; } /* Here come the first few lines... */ gon(); DRAW(tb); goff(); for (i=0; i<7; i++) { FromJulian(OrigJul+i, &y, &m, &d); sprintf(buf, "%d %c%c%c ", d, MonthName[m][0], MonthName[m][1], MonthName[m][2]); if (OrigJul+i == RealToday) PrintLeft(buf, ColSpaces, '*'); else PrintLeft(buf, ColSpaces, ' '); gon(); DRAW(tb); goff(); } PutChar('\n'); for (l=0; l11) { mm = 0; yy = y+1; } else yy=y; printf("%s %d\n", MonthName[mm], DaysInMonth(mm,yy)); } while (WriteCalendarRow()) continue; if (PsCal) printf("%s\n", PSEND); if (!DoSimpleCalendar) WriteCalTrailer(); } /***************************************************************/ /* */ /* WriteCalendarRow */ /* */ /* Write one row of the calendar */ /* */ /***************************************************************/ static int WriteCalendarRow(void) { int y, m, d, wd, i, l; int done; char buf[81]; int OrigJul = JulianToday; int LinesWritten = 0; int moreleft; /* Get the date of the first day */ FromJulian(JulianToday, &y, &m, &d); if (!MondayFirst) wd = (JulianToday + 1) % 7; else wd = JulianToday % 7; /* Fill in the column entries */ for (i=wd; i<7; i++) { if (d+i-wd > DaysInMonth(m, y)) break; GenerateCalEntries(i); JulianToday++; } /* Output the entries */ /* If it's "Simple Calendar" format, do it simply... */ if (DoSimpleCalendar) { for (i=wd; i<7 && d+i-wd<=DaysInMonth(m, y); i++) { WriteSimpleEntries(i, OrigJul+i-wd); } return (d+7-wd <= DaysInMonth(m, y)); } /* Here come the first few lines... */ gon(); DRAW(tb); goff(); for (i=0; i<7; i++) { if (i < wd || d+i-wd>DaysInMonth(m, y)) PrintLeft("", ColSpaces, ' '); else { sprintf(buf, "%d", d+i-wd); PrintLeft(buf, ColSpaces, ' '); } gon(); DRAW(tb); goff(); } PutChar('\n'); for (l=0; lwc_text) { wspace = NULL; ws = e->wc_pos; /* If we're at the end, and there's another entry, do a blank line and move to next entry. */ if (!*ws && e->next) { PrintLeft("", ColSpaces, ' '); CalColumn[col] = e->next; free((void *)e->text); free((void *)e->filename); if (e->wc_text) free((void *)e->wc_text); free(e); return 1; } /* Find the last space char within the column. */ while (ws - e->wc_pos <= ColSpaces) { if (!*ws) {wspace = ws; break;} if (iswspace(*ws)) wspace = ws; ws++; } /* Colorize reminder if necessary */ if (UseVTColors && e->is_color) { Colorize(e); } /* If we couldn't find a space char, print what we have. */ if (!wspace) { for (ws = e->wc_pos; ws - e->wc_pos < ColSpaces; ws++) { if (!*ws) break; numwritten++; PutWideChar(*ws); } e->wc_pos = ws; } else { /* We found a space - print everything before it. */ for (ws = e->wc_pos; wsis_color) { Decolorize(); } /* Flesh out the rest of the column */ while(numwritten++ < ColSpaces) PutChar(' '); /* Skip any spaces before next word */ while (iswspace(*ws)) ws++; /* If done, free memory if no next entry. */ if (!*ws && !e->next) { CalColumn[col] = e->next; free((void *)e->text); free((void *)e->filename); if (e->wc_text) free((void *)e->wc_text); free(e); } else { e->wc_pos = ws; } if (CalColumn[col]) return 1; else return 0; } else { #endif space = NULL; s = e->pos; /* If we're at the end, and there's another entry, do a blank line and move to next entry. */ if (!*s && e->next) { PrintLeft("", ColSpaces, ' '); CalColumn[col] = e->next; free((void *)e->text); free((void *)e->filename); #ifdef REM_USE_WCHAR if (e->wc_text) free((void *)e->wc_text); #endif free(e); return 1; } /* Find the last space char within the column. */ while (s - e->pos <= ColSpaces) { if (!*s) {space = s; break;} if (*s == ' ') space = s; s++; } /* Colorize reminder if necessary */ if (UseVTColors && e->is_color) { Colorize(e); } /* If we couldn't find a space char, print what we have. */ if (!space) { for (s = e->pos; s - e->pos < ColSpaces; s++) { if (!*s) break; numwritten++; PutChar(*s); } e->pos = s; } else { /* We found a space - print everything before it. */ for (s = e->pos; sis_color) { Decolorize(); } /* Flesh out the rest of the column */ while(numwritten++ < ColSpaces) PutChar(' '); /* Skip any spaces before next word */ while (*s == ' ') s++; /* If done, free memory if no next entry. */ if (!*s && !e->next) { CalColumn[col] = e->next; free((void *)e->text); free((void *)e->filename); #ifdef REM_USE_WCHAR if (e->wc_text) free((void *)e->wc_text); #endif free(e); } else { e->pos = s; } if (CalColumn[col]) return 1; else return 0; #ifdef REM_USE_WCHAR } #endif } /***************************************************************/ /* */ /* GenerateCalEntries */ /* */ /* Generate the calendar entries for the ith column */ /* */ /***************************************************************/ static void GenerateCalEntries(int col) { int r; Token tok; char const *s; Parser p; /* Do some initialization first... */ ClearGlobalOmits(); DestroyOmitContexts(); DestroyVars(0); NumTriggered = 0; r=IncludeFile(InitialFile); if (r) { fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING], InitialFile, ErrMsg[r]); exit(1); } while(1) { r = ReadLine(); if (r == E_EOF) return; if (r) { Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]); exit(1); } s = FindInitialToken(&tok, CurLine); /* Should we ignore it? */ if (NumIfs && tok.type != T_If && tok.type != T_Else && tok.type != T_EndIf && tok.type != T_IfTrig && ShouldIgnoreLine()) { /* DO NOTHING */ } else { /* Create a parser to parse the line */ CreateParser(s, &p); switch(tok.type) { case T_Empty: case T_Comment: break; case T_ErrMsg: r=DoErrMsg(&p); break; case T_Rem: r=DoCalRem(&p, col); break; case T_If: r=DoIf(&p); break; case T_IfTrig: r=DoIfTrig(&p); break; case T_Else: r=DoElse(&p); break; case T_EndIf: r=DoEndif(&p); break; case T_Include: r=DoInclude(&p); break; case T_Exit: DoExit(&p); break; case T_Set: r=DoSet(&p); break; case T_Fset: r=DoFset(&p); break; case T_UnSet: r=DoUnset(&p); break; case T_Clr: r=DoClear(&p); break; case T_Flush: r=DoFlush(&p); break; case T_Debug: break; /* IGNORE DEBUG CMD */ case T_Dumpvars: break; /* IGNORE DUMPVARS CMD */ case T_Banner: break; /* IGNORE BANNER CMD */ case T_Omit: r=DoOmit(&p); if (r == E_PARSE_AS_REM) { DestroyParser(&p); CreateParser(s, &p); r=DoCalRem(&p, col); } break; case T_Pop: r=PopOmitContext(&p); break; case T_Push: r=PushOmitContext(&p); break; case T_Preserve: r=DoPreserve(&p); break; case T_RemType: if (tok.val == RUN_TYPE) { r=DoRun(&p); break; } else { CreateParser(CurLine, &p); r=DoCalRem(&p, col); break; } /* If we don't recognize the command, do a REM by default */ /* Note: Since the parser hasn't been used yet, we don't */ /* need to destroy it here. */ default: CreateParser(CurLine, &p); r=DoCalRem(&p, col); break; } if (r && (!Hush || r != E_RUN_DISABLED)) Eprint("%s", ErrMsg[r]); /* Destroy the parser - free up resources it may be tying up */ DestroyParser(&p); } } } /***************************************************************/ /* */ /* WriteCalHeader */ /* */ /***************************************************************/ static void WriteCalHeader(void) { char buf[80]; int y, m, d; FromJulian(JulianToday, &y, &m, &d); sprintf(buf, "%s %d", MonthName[m], y); WriteTopCalLine(); gon(); DRAW(tb); goff(); PrintCentered(buf, CalWidth-2, " "); gon(); DRAW(tb); goff(); PutChar('\n'); WritePostHeaderLine(); WriteCalDays(); WriteIntermediateCalLine(); } /***************************************************************/ /* */ /* WriteCalTrailer */ /* */ /***************************************************************/ static void WriteCalTrailer(void) { PutChar('\f'); } /***************************************************************/ /* */ /* DoCalRem */ /* */ /* Do the REM command in the context of a calendar. */ /* */ /***************************************************************/ static int DoCalRem(ParsePtr p, int col) { int oldLen; Trigger trig; TimeTrig tim; Value v; int r, err; int jul; CalEntry *CurCol = CalColumn[col]; CalEntry *e; char const *s, *s2; DynamicBuffer buf, obuf, pre_buf; Token tok; int is_color, col_r, col_g, col_b; is_color = 0; DBufInit(&buf); DBufInit(&pre_buf); /* Parse the trigger date and time */ if ( (r=ParseRem(p, &trig, &tim, 1)) ) { FreeTrig(&trig); return r; } /* Don't include timed reminders in calendar if -a option supplied. */ if (DontIssueAts && tim.ttime != NO_TIME) { FreeTrig(&trig); return OK; } if (trig.typ == NO_TYPE) { FreeTrig(&trig); return E_EOLN; } if (trig.typ == SAT_TYPE) { r=DoSatRemind(&trig, &tim, p); if (r) { FreeTrig(&trig); if (r == E_EXPIRED) return OK; return r; } if (!LastTrigValid) { FreeTrig(&trig); return OK; } r=ParseToken(p, &buf); if (r) { FreeTrig(&trig); return r; } FindToken(DBufValue(&buf), &tok); DBufFree(&buf); if (tok.type == T_Empty || tok.type == T_Comment) { FreeTrig(&trig); return OK; } if (tok.type != T_RemType || tok.val == SAT_TYPE) { FreeTrig(&trig); return E_PARSE_ERR; } if (tok.val == PASSTHRU_TYPE) { r=ParseToken(p, &buf); if (r) return r; if (!DBufLen(&buf)) { DBufFree(&buf); FreeTrig(&trig); return E_EOLN; } StrnCpy(trig.passthru, DBufValue(&buf), PASSTHRU_LEN); DBufFree(&buf); } trig.typ = tok.val; jul = LastTriggerDate; if (!LastTrigValid) { FreeTrig(&trig); return OK; } } else { /* Calculate the trigger date */ jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1); if (r) { FreeTrig(&trig); return r; } } /* Convert PS and PSF to PASSTHRU */ if (trig.typ == PS_TYPE) { strcpy(trig.passthru, "PostScript"); trig.typ = PASSTHRU_TYPE; } else if (trig.typ == PSF_TYPE) { strcpy(trig.passthru, "PSFile"); trig.typ = PASSTHRU_TYPE; } if (trig.typ == PASSTHRU_TYPE) { if (!PsCal && strcmp(trig.passthru, "COLOR") && strcmp(trig.passthru, "COLOUR")) { FreeTrig(&trig); return OK; } if (!strcmp(trig.passthru, "COLOR") || !strcmp(trig.passthru, "COLOUR")) { is_color = 1; /* Strip off the three color numbers */ DBufFree(&buf); r=ParseToken(p, &buf); DBufPuts(&pre_buf, DBufValue(&buf)); DBufPutc(&pre_buf, ' '); DBufFree(&buf); if (r) { FreeTrig(&trig); return r; } r=ParseToken(p, &buf); DBufPuts(&pre_buf, DBufValue(&buf)); DBufPutc(&pre_buf, ' '); DBufFree(&buf); if (r) { FreeTrig(&trig); return r; } r=ParseToken(p, &buf); DBufPuts(&pre_buf, DBufValue(&buf)); DBufPutc(&pre_buf, ' '); DBufFree(&buf); if (r) { FreeTrig(&trig); return r; } (void) sscanf(DBufValue(&pre_buf), "%d %d %d", &col_r, &col_g, &col_b); if (col_r < 0) col_r = 0; else if (col_r > 255) col_r = 255; if (col_g < 0) col_g = 0; else if (col_g > 255) col_g = 255; if (col_b < 0) col_b = 0; else if (col_b > 255) col_b = 255; if (!PsCal && !DoSimpleCalendar) { DBufFree(&pre_buf); } } } /* If trigger date == today, add it to the current entry */ DBufInit(&obuf); if ((jul == JulianToday) || (DoSimpleCalDelta && ShouldTriggerReminder(&trig, &tim, jul, &err))) { NumTriggered++; if (DoSimpleCalendar || tim.ttime != NO_TIME) { /* Suppress time if it's not today or if it's a non-COLOR special */ if (jul != JulianToday || (trig.typ == PASSTHRU_TYPE && strcmp(trig.passthru, "COLOUR") && strcmp(trig.passthru, "COLOR"))) { if (DBufPuts(&obuf, SimpleTime(NO_TIME)) != OK) { DBufFree(&obuf); DBufFree(&pre_buf); FreeTrig(&trig); return E_NO_MEM; } } else { if (DBufPuts(&obuf, CalendarTime(tim.ttime, tim.duration)) != OK) { DBufFree(&obuf); DBufFree(&pre_buf); FreeTrig(&trig); return E_NO_MEM; } } } if (trig.typ != PASSTHRU_TYPE && UserFuncExists("calprefix")==1) { char evalBuf[64]; sprintf(evalBuf, "calprefix(%d)", trig.priority); s2 = evalBuf; r = EvalExpr(&s2, &v, NULL); if (!r) { if (!DoCoerce(STR_TYPE, &v)) { if (DBufPuts(&obuf, v.v.str) != OK) { DestroyValue(v); DBufFree(&obuf); DBufFree(&pre_buf); FreeTrig(&trig); return E_NO_MEM; } } DestroyValue(v); } } oldLen = DBufLen(&obuf); /* In -sa mode, run in ADVANCE mode if we're triggering * before the actual date */ if (jul != JulianToday) { r = DoSubst(p, &obuf, &trig, &tim, jul, ADVANCE_MODE); } else { r = DoSubst(p, &obuf, &trig, &tim, jul, CAL_MODE); } if (r) { DBufFree(&pre_buf); DBufFree(&obuf); FreeTrig(&trig); return r; } if (DBufLen(&obuf) <= oldLen) { DBufFree(&obuf); DBufFree(&pre_buf); FreeTrig(&trig); return OK; } if (trig.typ != PASSTHRU_TYPE && UserFuncExists("calsuffix")==1) { char evalBuf[64]; sprintf(evalBuf, "calsuffix(%d)", trig.priority); s2 = evalBuf; r = EvalExpr(&s2, &v, NULL); if (!r) { if (!DoCoerce(STR_TYPE, &v)) { if (DBufPuts(&obuf, v.v.str) != OK) { DestroyValue(v); DBufFree(&obuf); DBufFree(&pre_buf); FreeTrig(&trig); return E_NO_MEM; } } DestroyValue(v); } } s = DBufValue(&obuf); if (!DoSimpleCalendar) while (isempty(*s)) s++; DBufPuts(&pre_buf, s); s = DBufValue(&pre_buf); e = NEW(CalEntry); if (!e) { DBufFree(&obuf); DBufFree(&pre_buf); FreeTrig(&trig); return E_NO_MEM; } #ifdef REM_USE_WCHAR e->wc_pos = NULL; e->wc_text = NULL; #endif e->is_color = is_color; e->r = col_r; e->g = col_g; e->b = col_b; e->text = StrDup(s); DBufFree(&obuf); DBufFree(&pre_buf); if (!e->text) { free(e); FreeTrig(&trig); return E_NO_MEM; } make_wchar_versions(e); DBufInit(&(e->tags)); DBufPuts(&(e->tags), DBufValue(&(trig.tags))); if (SynthesizeTags) { AppendTag(&(e->tags), SynthesizeTag()); } /* Don't need tags any more */ FreeTrig(&trig); e->duration = tim.duration; e->priority = trig.priority; e->filename = StrDup(FileName); if(!e->filename) { free(e); return E_NO_MEM; } e->lineno = LineNo; if (trig.typ == PASSTHRU_TYPE) { StrnCpy(e->passthru, trig.passthru, PASSTHRU_LEN); } else { e->passthru[0] = 0; } e->pos = e->text; if (jul == JulianToday) { e->time = tim.ttime; } else { e->time = NO_TIME; } e->next = CurCol; CalColumn[col] = e; SortCol(&CalColumn[col]); } return OK; } /***************************************************************/ /* */ /* WriteSimpleEntries */ /* */ /* Write entries in 'simple calendar' format. */ /* */ /***************************************************************/ static void WriteSimpleEntries(int col, int jul) { CalEntry *e = CalColumn[col]; CalEntry *n; int y, m, d; FromJulian(jul, &y, &m, &d); while(e) { if (DoPrefixLineNo) printf("# fileinfo %d %s\n", e->lineno, e->filename); printf("%04d/%02d/%02d", y, m+1, d); if (e->passthru[0]) { printf(" %s", e->passthru); } else { printf(" *"); } if (*DBufValue(&(e->tags))) { printf(" %s ", DBufValue(&(e->tags))); } else { printf(" * "); } if (e->duration != NO_TIME) { printf("%d ", e->duration); } else { printf("* "); } if (e->time != NO_TIME) { printf("%d ", e->time); } else { printf("* "); } printf("%s\n", e->text); free((void *)e->text); free((void *)e->filename); #ifdef REM_USE_WCHAR if (e->wc_text) free((void *)e->wc_text); #endif n = e->next; free(e); e = n; } CalColumn[col] = NULL; } /***************************************************************/ /* */ /* Various functions for writing different types of lines. */ /* */ /***************************************************************/ static void WriteTopCalLine(void) { gon(); DRAW(br); PrintCentered("", CalWidth-2, linestruct->lr); DRAW(bl); goff(); PutChar('\n'); } static void WriteBottomCalLine(void) { int i; gon(); DRAW(tr); for (i=0; i<7; i++) { PrintCentered("", ColSpaces, linestruct->lr); if (i != 6) { DRAW(tlr); } else { DRAW(tl); } } goff(); PutChar('\n'); } static void WritePostHeaderLine(void) { int i; gon(); DRAW(tbr); for (i=0; i<7; i++) { PrintCentered("", ColSpaces, linestruct->lr); if (i != 6) { DRAW(blr); } else { DRAW(tbl); } } goff(); PutChar('\n'); } static void WriteWeekHeaderLine(void) { int i; gon(); DRAW(br); for (i=0; i<7; i++) { PrintCentered("", ColSpaces, linestruct->lr); if (i != 6) { DRAW(blr); } else { DRAW(bl); } } goff(); PutChar('\n'); } static void WriteIntermediateCalLine(void) { int i; gon(); DRAW(tbr); for (i=0; i<7; i++) { PrintCentered("", ColSpaces, linestruct->lr); if (i != 6) { DRAW(tblr); } else { DRAW(tbl); } } goff(); PutChar('\n'); } static void WriteCalDays(void) { int i; gon(); DRAW(tb); goff(); for (i=0; i<7; i++) { if (!MondayFirst) PrintCentered(DayName[(i+6)%7], ColSpaces, " "); else PrintCentered(DayName[i%7], ColSpaces, " "); gon(); DRAW(tb); goff(); } PutChar('\n'); } /***************************************************************/ /* */ /* CalendarTime */ /* */ /* Format the time according to simple time format. */ /* Answer is returned in a static buffer. */ /* A trailing space is always added. */ /* This takes into account duration */ /* */ /***************************************************************/ char const * CalendarTime(int tim, int duration) { static char buf[128]; int h, min, hh; int h2, min2, hh2, newtim, days; char const *ampm1; char const *ampm2; char daybuf[64]; buf[0] = 0; if (duration == NO_TIME) { /* No duration... just call into SimpleTime */ return SimpleTime(tim); } if (tim == NO_TIME) { /* No time... nothing to return */ return buf; } h = tim/60; min = tim % 60; if (h == 0) hh=12; else if (h > 12) hh=h-12; else hh = h; newtim = tim + duration; /* How many days in duration? */ days = newtim / MINUTES_PER_DAY; newtim = newtim % MINUTES_PER_DAY; h2 = newtim/60; min2 = newtim % 60; if (h2 == 0) hh2=12; else if (h2 > 12) hh2=h2-12; else hh2 = h2; if (days) { sprintf(daybuf, "+%d", days); } else { daybuf[0] = 0; } if (h >= 12) { ampm1 = L_PM; } else { ampm1 = L_AM; } if (h2 >= 12) { ampm2 = L_PM; } else { ampm2 = L_AM; } if (!days) { if (!strcmp(ampm1, ampm2)) { ampm1 = ""; } } switch(ScFormat) { case SC_AMPM: sprintf(buf, "%d%c%02d%s-%d%c%02d%s%s ", hh, TimeSep, min, ampm1, hh2, TimeSep, min2, ampm2, daybuf); break; case SC_MIL: sprintf(buf, "%02d%c%02d-%02d%c%02d%s ", h, TimeSep, min, h2, TimeSep, min2, daybuf); break; } return buf; } /***************************************************************/ /* */ /* SimpleTime */ /* */ /* Format the time according to simple time format. */ /* Answer is returned in a static buffer. */ /* A trailing space is always added. */ /* */ /***************************************************************/ char const *SimpleTime(int tim) { static char buf[32]; int h, min, hh; buf[0] = 0; switch(ScFormat) { case SC_AMPM: if (tim != NO_TIME) { h = tim / 60; min = tim % 60; if (h == 0) hh=12; else if (h > 12) hh=h-12; else hh=h; sprintf(buf, "%d%c%02d%s ", hh, TimeSep, min, (h>=12) ? L_PM : L_AM); } break; case SC_MIL: if (tim != NO_TIME) { h = tim / 60; min = tim % 60; sprintf(buf, "%02d%c%02d ", h, TimeSep, min); } break; } return buf; } /***************************************************************/ /* */ /* SortCol */ /* */ /* Sort the calendar entries in a column by time and priority */ /* */ /***************************************************************/ static void SortCol(CalEntry **col) { CalEntry *cur, *prev, *next; cur = *col; prev = NULL; /* Note that we use <= comparison rather than > comparison to preserve the file order of reminders which have the same time and priority */ while (cur->next && CompareRems(0, cur->time, cur->priority, 0, cur->next->time, cur->next->priority, SortByDate, SortByTime, SortByPrio, UntimedBeforeTimed) <= 0) { next = cur->next; /* Swap cur and next */ if (!prev) { *col = next; cur->next = next->next; next->next = cur; prev = next; } else { prev->next = next; cur->next = next->next; next->next = cur; prev = next; } } } char const *SynthesizeTag(void) { struct MD5Context ctx; unsigned char buf[16]; static char out[128]; MD5Init(&ctx); MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine)); MD5Final(buf, &ctx); sprintf(out, "__syn__%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", (unsigned int) buf[0], (unsigned int) buf[1], (unsigned int) buf[2], (unsigned int) buf[3], (unsigned int) buf[4], (unsigned int) buf[5], (unsigned int) buf[6], (unsigned int) buf[7], (unsigned int) buf[8], (unsigned int) buf[9], (unsigned int) buf[10], (unsigned int) buf[11], (unsigned int) buf[12], (unsigned int) buf[13], (unsigned int) buf[14], (unsigned int) buf[15]); return out; } remind-03.01.15/src/config.h.in0000644000076400007640000000146511442247550014165 0ustar dfsdfs/* Define if utime(file, NULL) sets file's timestamp to the present. */ #undef HAVE_UTIME_NULL /* Define if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define if your declares struct tm. */ #undef TM_IN_SYS_TIME /* Define if you have the header file. */ #undef HAVE_SYS_FILE_H /* Define if you have the header file */ #undef HAVE_GLOB_H #undef HAVE_WCTYPE_H #undef HAVE_LOCALE_H #undef HAVE_GLOB #undef HAVE_SETENV #undef HAVE_UNSETENV #undef HAVE_MBSTOWCS #undef HAVE_SETLOCALE /* The number of bytes in a unsigned int. */ #undef SIZEOF_UNSIGNED_INT /* The number of bytes in a unsigned long. */ #undef SIZEOF_UNSIGNED_LONG /* The number of bytes in a unsigned short. */ #undef SIZEOF_UNSIGNED_SHORT #include "custom.h" remind-03.01.15/src/custom.h0000644000076400007640000002670712516507332013633 0ustar dfsdfs/***************************************************************/ /* */ /* CUSTOM.H.IN */ /* */ /* Contains various configuration parameters for Remind */ /* which you can customize. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /*---------------------------------------------------------------------*/ /* LAT_DEG, LAT_MIN and LAT_SEC: Latitude of your location */ /* LON_DEG, LON_MIN and LON_SEC: Longitude of your location */ /* LOCATION: A string identifying your location. */ /* All latitude and longitude numbers should be positive for the */ /* northern and western hemisphere. If you live in the southern */ /* hemisphere, ALL latitude values should be negative. If you live */ /* in the eastern hemisphere, ALL longitude values should be negative. */ /* */ /* The default values are initially set to Ottawa, Ontario, Canada. */ /*---------------------------------------------------------------------*/ #define LAT_DEG 45 #define LAT_MIN 24 #define LAT_SEC 0 #define LON_DEG 75 #define LON_MIN 39 #define LON_SEC 0 #define LOCATION "Ottawa" /*---------------------------------------------------------------------*/ /* DEFAULT_PAGE: The default page size to use for Rem2PS. */ /* The Letter version is appropriate for North America; the A4 version */ /* is appropriate for Europe. */ /*---------------------------------------------------------------------*/ #define DEFAULT_PAGE {"Letter", 612, 792} /* #define DEFAULT_PAGE {"A4", 595, 842} */ /*---------------------------------------------------------------------*/ /* DATESEP: The default date separator. Standard usage is '-'; */ /* others may prefer '/'. */ /*---------------------------------------------------------------------*/ #define DATESEP '-' /* #define DATESEP '/' */ /*---------------------------------------------------------------------*/ /* TIMESEP: The default time separator. North American usage is ':'; */ /* others may prefer '.'. */ /*---------------------------------------------------------------------*/ #define TIMESEP ':' /* #define TIMESEP '.' */ /*---------------------------------------------------------------------*/ /* ISOLATIN1: define it to 1 if you use the */ /* ISO 8859-1 character set instead of ASCII. */ /*---------------------------------------------------------------------*/ #define ISOLATIN1 1 /*---------------------------------------------------------------------*/ /* ISOLATIN2: define it to 1 if you use the */ /* ISO 8859-2 character set instead of ASCII. */ /* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */ /* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */ /* then one are defined as 1, the results are unspecified. */ /*---------------------------------------------------------------------*/ #define ISOLATIN2 0 /*---------------------------------------------------------------------*/ /* IBMEXTENDED: define as 1 if your system uses the IBM extended */ /* character set. */ /* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */ /* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */ /* then one are defined as 1, the results are unspecified. */ /*---------------------------------------------------------------------*/ #define IBMEXTENDED 0 /*---------------------------------------------------------------------*/ /* IBM852: define as 1 if your system uses the IBM CPI-852 extended */ /* character set. */ /* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */ /* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */ /* then one are defined as 1, the results are unspecified. */ /*---------------------------------------------------------------------*/ #define IBM852 0 /*---------------------------------------------------------------------*/ /* WANT_U_OPTION: Comment out the next define to permanently disable */ /* the -u option. */ /*---------------------------------------------------------------------*/ #define WANT_U_OPTION 1 /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /* You most likely do NOT have to tweak anything after this! */ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /*---------------------------------------------------------------------*/ /* WANT_SHELL_ESCAPING: Define this if you want special shell */ /* characters to be escaped with a backslash for the -k option. */ /*---------------------------------------------------------------------*/ #if defined(UNIX) #define WANT_SHELL_ESCAPING 1 #endif /*---------------------------------------------------------------------*/ /* Some implementations have a broken 'putc' and 'putchar'. */ /*---------------------------------------------------------------------*/ #ifdef __SASC_60 #define BROKEN_PUTC #endif /*---------------------------------------------------------------------*/ /* BASE: The base year for date calculation. NOTE! January 1 of the */ /* base year MUST be a Monday, else Remind will not work! */ /* IMPORTANT NOTE: The Hebrew date routines depend on BASE */ /* being set to 1990. If you change it, you'll have to add the */ /* number of days between 1 Jan and 1 Jan 1990 to the */ /* manifest constant CORRECTION in hbcal.c. Also, the year */ /* folding mechanism in main.c depends on BASE<2001. */ /*---------------------------------------------------------------------*/ #define BASE 1990 /*---------------------------------------------------------------------*/ /* YR_RANGE: The range of years allowed. With 32-bit signed integers, */ /* the DATETIME type can store 2^31 minutes or about 4074 years. */ /*---------------------------------------------------------------------*/ #define YR_RANGE 4000 /*---------------------------------------------------------------------*/ /* VAR_NAME_LEN: The maximum length of variable names. Don't make it */ /* any less than 12. */ /*---------------------------------------------------------------------*/ #define VAR_NAME_LEN 16 /*---------------------------------------------------------------------*/ /* MAX_PRT_LEN: The maximum number of characters to print when */ /* displaying a string value for debugging purposes. */ /*---------------------------------------------------------------------*/ #define MAX_PRT_LEN 40 /*---------------------------------------------------------------------*/ /* MAX_STR_LEN: If non-zero, Remind will limit the maximum length */ /* of string values to avoid eating up all of memory... */ /*---------------------------------------------------------------------*/ #define MAX_STR_LEN 65535 /*---------------------------------------------------------------------*/ /* OP_STACK_SIZE: The size of the operator stack for expr. parsing */ /*---------------------------------------------------------------------*/ #define OP_STACK_SIZE 100 /*---------------------------------------------------------------------*/ /* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */ /*---------------------------------------------------------------------*/ #define VAL_STACK_SIZE 500 /*---------------------------------------------------------------------*/ /* INCLUDE_NEST: How many nested INCLUDES do we handle? */ /*---------------------------------------------------------------------*/ #define INCLUDE_NEST 9 /*---------------------------------------------------------------------*/ /* IF_NEST: How many nested IFs do we handle? Maximum is the number */ /* of bits in an int, divided by two. Beware! */ /*---------------------------------------------------------------------*/ #define IF_NEST (4*sizeof(unsigned int)) /*---------------------------------------------------------------------*/ /* How many attempts to resolve a weird date spec? */ /*---------------------------------------------------------------------*/ #define TRIG_ATTEMPTS 500 /*---------------------------------------------------------------------*/ /* How many global omits of the form YYYY MM DD do we handle? */ /*---------------------------------------------------------------------*/ #define MAX_FULL_OMITS 500 /*---------------------------------------------------------------------*/ /* How many global omits of the form MM DD do we handle? */ /*---------------------------------------------------------------------*/ #define MAX_PARTIAL_OMITS 366 /*---------------------------------------------------------------------*/ /* A newline - some systems need "\n\r" */ /*---------------------------------------------------------------------*/ #define NL "\n" /*---------------------------------------------------------------------*/ /* Minimum number of linefeeds in each calendar "box" */ /*---------------------------------------------------------------------*/ #define CAL_LINES 5 /*---------------------------------------------------------------------*/ /* Don't change the next definitions */ /*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/ /* TAG_LEN: The maximum length of tags. Don't change it */ /*---------------------------------------------------------------------*/ #define TAG_LEN 48 #define PASSTHRU_LEN 32 #define PSBEGIN "# rem2ps begin" #define PSEND "# rem2ps end" #ifdef BROKEN_PUTC #define Putc SafePutc #define PutChar SafePutChar #else #define Putc putc #define PutChar putchar #endif #if defined(HAVE_MBSTOWCS) && defined(HAVE_WCTYPE_H) #define REM_USE_WCHAR 1 #else #undef REM_USE_WCHAR #endif remind-03.01.15/src/custom.h.in0000644000076400007640000002670712514120772014235 0ustar dfsdfs/***************************************************************/ /* */ /* CUSTOM.H.IN */ /* */ /* Contains various configuration parameters for Remind */ /* which you can customize. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /*---------------------------------------------------------------------*/ /* LAT_DEG, LAT_MIN and LAT_SEC: Latitude of your location */ /* LON_DEG, LON_MIN and LON_SEC: Longitude of your location */ /* LOCATION: A string identifying your location. */ /* All latitude and longitude numbers should be positive for the */ /* northern and western hemisphere. If you live in the southern */ /* hemisphere, ALL latitude values should be negative. If you live */ /* in the eastern hemisphere, ALL longitude values should be negative. */ /* */ /* The default values are initially set to Ottawa, Ontario, Canada. */ /*---------------------------------------------------------------------*/ #define LAT_DEG 45 #define LAT_MIN 24 #define LAT_SEC 0 #define LON_DEG 75 #define LON_MIN 39 #define LON_SEC 0 #define LOCATION "Ottawa" /*---------------------------------------------------------------------*/ /* DEFAULT_PAGE: The default page size to use for Rem2PS. */ /* The Letter version is appropriate for North America; the A4 version */ /* is appropriate for Europe. */ /*---------------------------------------------------------------------*/ #define DEFAULT_PAGE {"Letter", 612, 792} /* #define DEFAULT_PAGE {"A4", 595, 842} */ /*---------------------------------------------------------------------*/ /* DATESEP: The default date separator. Standard usage is '-'; */ /* others may prefer '/'. */ /*---------------------------------------------------------------------*/ #define DATESEP '-' /* #define DATESEP '/' */ /*---------------------------------------------------------------------*/ /* TIMESEP: The default time separator. North American usage is ':'; */ /* others may prefer '.'. */ /*---------------------------------------------------------------------*/ #define TIMESEP ':' /* #define TIMESEP '.' */ /*---------------------------------------------------------------------*/ /* ISOLATIN1: define it to 1 if you use the */ /* ISO 8859-1 character set instead of ASCII. */ /*---------------------------------------------------------------------*/ #define ISOLATIN1 1 /*---------------------------------------------------------------------*/ /* ISOLATIN2: define it to 1 if you use the */ /* ISO 8859-2 character set instead of ASCII. */ /* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */ /* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */ /* then one are defined as 1, the results are unspecified. */ /*---------------------------------------------------------------------*/ #define ISOLATIN2 0 /*---------------------------------------------------------------------*/ /* IBMEXTENDED: define as 1 if your system uses the IBM extended */ /* character set. */ /* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */ /* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */ /* then one are defined as 1, the results are unspecified. */ /*---------------------------------------------------------------------*/ #define IBMEXTENDED 0 /*---------------------------------------------------------------------*/ /* IBM852: define as 1 if your system uses the IBM CPI-852 extended */ /* character set. */ /* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */ /* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */ /* then one are defined as 1, the results are unspecified. */ /*---------------------------------------------------------------------*/ #define IBM852 0 /*---------------------------------------------------------------------*/ /* WANT_U_OPTION: Comment out the next define to permanently disable */ /* the -u option. */ /*---------------------------------------------------------------------*/ #define WANT_U_OPTION 1 /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /* You most likely do NOT have to tweak anything after this! */ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /*---------------------------------------------------------------------*/ /* WANT_SHELL_ESCAPING: Define this if you want special shell */ /* characters to be escaped with a backslash for the -k option. */ /*---------------------------------------------------------------------*/ #if defined(UNIX) #define WANT_SHELL_ESCAPING 1 #endif /*---------------------------------------------------------------------*/ /* Some implementations have a broken 'putc' and 'putchar'. */ /*---------------------------------------------------------------------*/ #ifdef __SASC_60 #define BROKEN_PUTC #endif /*---------------------------------------------------------------------*/ /* BASE: The base year for date calculation. NOTE! January 1 of the */ /* base year MUST be a Monday, else Remind will not work! */ /* IMPORTANT NOTE: The Hebrew date routines depend on BASE */ /* being set to 1990. If you change it, you'll have to add the */ /* number of days between 1 Jan and 1 Jan 1990 to the */ /* manifest constant CORRECTION in hbcal.c. Also, the year */ /* folding mechanism in main.c depends on BASE<2001. */ /*---------------------------------------------------------------------*/ #define BASE 1990 /*---------------------------------------------------------------------*/ /* YR_RANGE: The range of years allowed. With 32-bit signed integers, */ /* the DATETIME type can store 2^31 minutes or about 4074 years. */ /*---------------------------------------------------------------------*/ #define YR_RANGE 4000 /*---------------------------------------------------------------------*/ /* VAR_NAME_LEN: The maximum length of variable names. Don't make it */ /* any less than 12. */ /*---------------------------------------------------------------------*/ #define VAR_NAME_LEN 16 /*---------------------------------------------------------------------*/ /* MAX_PRT_LEN: The maximum number of characters to print when */ /* displaying a string value for debugging purposes. */ /*---------------------------------------------------------------------*/ #define MAX_PRT_LEN 40 /*---------------------------------------------------------------------*/ /* MAX_STR_LEN: If non-zero, Remind will limit the maximum length */ /* of string values to avoid eating up all of memory... */ /*---------------------------------------------------------------------*/ #define MAX_STR_LEN 65535 /*---------------------------------------------------------------------*/ /* OP_STACK_SIZE: The size of the operator stack for expr. parsing */ /*---------------------------------------------------------------------*/ #define OP_STACK_SIZE 100 /*---------------------------------------------------------------------*/ /* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */ /*---------------------------------------------------------------------*/ #define VAL_STACK_SIZE 500 /*---------------------------------------------------------------------*/ /* INCLUDE_NEST: How many nested INCLUDES do we handle? */ /*---------------------------------------------------------------------*/ #define INCLUDE_NEST 9 /*---------------------------------------------------------------------*/ /* IF_NEST: How many nested IFs do we handle? Maximum is the number */ /* of bits in an int, divided by two. Beware! */ /*---------------------------------------------------------------------*/ #define IF_NEST (4*sizeof(unsigned int)) /*---------------------------------------------------------------------*/ /* How many attempts to resolve a weird date spec? */ /*---------------------------------------------------------------------*/ #define TRIG_ATTEMPTS 500 /*---------------------------------------------------------------------*/ /* How many global omits of the form YYYY MM DD do we handle? */ /*---------------------------------------------------------------------*/ #define MAX_FULL_OMITS 500 /*---------------------------------------------------------------------*/ /* How many global omits of the form MM DD do we handle? */ /*---------------------------------------------------------------------*/ #define MAX_PARTIAL_OMITS 366 /*---------------------------------------------------------------------*/ /* A newline - some systems need "\n\r" */ /*---------------------------------------------------------------------*/ #define NL "\n" /*---------------------------------------------------------------------*/ /* Minimum number of linefeeds in each calendar "box" */ /*---------------------------------------------------------------------*/ #define CAL_LINES 5 /*---------------------------------------------------------------------*/ /* Don't change the next definitions */ /*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/ /* TAG_LEN: The maximum length of tags. Don't change it */ /*---------------------------------------------------------------------*/ #define TAG_LEN 48 #define PASSTHRU_LEN 32 #define PSBEGIN "# rem2ps begin" #define PSEND "# rem2ps end" #ifdef BROKEN_PUTC #define Putc SafePutc #define PutChar SafePutChar #else #define Putc putc #define PutChar putchar #endif #if defined(HAVE_MBSTOWCS) && defined(HAVE_WCTYPE_H) #define REM_USE_WCHAR 1 #else #undef REM_USE_WCHAR #endif remind-03.01.15/src/dorem.c0000644000076400007640000007377412531376363013435 0ustar dfsdfs/***************************************************************/ /* */ /* DOREM.C */ /* */ /* Contains routines for parsing reminders and evaluating */ /* triggers. Also contains routines for parsing OMIT */ /* commands. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #include "globals.h" #include "err.h" #include "types.h" #include "protos.h" #include "expr.h" /* Define the shell characters not to escape */ static char const DontEscapeMe[] = "1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,"; static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals); static int ParseLocalOmit (ParsePtr s, Trigger *t); static int ParseScanFrom (ParsePtr s, Trigger *t, int type); static int ParsePriority (ParsePtr s, Trigger *t); static int ParseUntil (ParsePtr s, Trigger *t); static int ShouldTriggerBasedOnWarn (Trigger *t, int jul, int *err); /***************************************************************/ /* */ /* DoRem */ /* */ /* Do the REM command. */ /* */ /***************************************************************/ int DoRem(ParsePtr p) { Trigger trig; TimeTrig tim; int r, err; int jul; DynamicBuffer buf; Token tok; DBufInit(&buf); /* Parse the trigger date and time */ if ( (r=ParseRem(p, &trig, &tim, 1)) ) { FreeTrig(&trig); return r; } if (trig.typ == NO_TYPE) { PurgeEchoLine("%s\n%s\n", "#!P! Cannot parse next line", CurLine); FreeTrig(&trig); return E_EOLN; } if (trig.typ == SAT_TYPE) { PurgeEchoLine("%s\n", "#!P: Cannot purge SATISFY-type reminders"); PurgeEchoLine("%s\n", CurLine); r=DoSatRemind(&trig, &tim, p); if (r) { FreeTrig(&trig); if (r == E_EXPIRED) return OK; return r; } if (!LastTrigValid) { FreeTrig(&trig); return OK; } r=ParseToken(p, &buf); if (r) { FreeTrig(&trig); return r; } FindToken(DBufValue(&buf), &tok); DBufFree(&buf); if (tok.type == T_Empty || tok.type == T_Comment) { DBufFree(&buf); FreeTrig(&trig); return OK; } if (tok.type != T_RemType || tok.val == SAT_TYPE) { DBufFree(&buf); FreeTrig(&trig); return E_PARSE_ERR; } if (tok.val == PASSTHRU_TYPE) { r=ParseToken(p, &buf); if (r) { FreeTrig(&trig); return r; } if (!DBufLen(&buf)) { FreeTrig(&trig); DBufFree(&buf); return E_EOLN; } StrnCpy(trig.passthru, DBufValue(&buf), PASSTHRU_LEN); DBufFree(&buf); } trig.typ = tok.val; jul = LastTriggerDate; if (!LastTrigValid || PurgeMode) { FreeTrig(&trig); return OK; } } else { /* Calculate the trigger date */ jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1); if (r) { if (PurgeMode) { PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", ErrMsg[r]); PurgeEchoLine("%s\n", CurLine); } FreeTrig(&trig); return r; } } if (PurgeMode) { if (trig.expired || jul < JulianToday) { if (p->expr_happened) { if (p->nonconst_expr) { PurgeEchoLine("%s\n", "#!P: Next line may have expired, but contains non-constant expression"); PurgeEchoLine("%s\n", CurLine); } else { PurgeEchoLine("%s\n", "#!P: Next line has expired, but contains expression... please verify"); PurgeEchoLine("#!P: Expired: %s\n", CurLine); } } else { PurgeEchoLine("#!P: Expired: %s\n", CurLine); } } else { PurgeEchoLine("%s\n", CurLine); } FreeTrig(&trig); return OK; } /* Queue the reminder, if necessary */ if (jul == JulianToday && !(!IgnoreOnce && trig.once != NO_ONCE && FileAccessDate == JulianToday)) QueueReminder(p, &trig, &tim, trig.sched); /* If we're in daemon mode, do nothing over here */ if (Daemon) { FreeTrig(&trig); return OK; } if (ShouldTriggerReminder(&trig, &tim, jul, &err)) { if ( (r=TriggerReminder(p, &trig, &tim, jul)) ) { FreeTrig(&trig); return r; } } FreeTrig(&trig); return OK; } /***************************************************************/ /* */ /* ParseRem */ /* */ /* Given a parse pointer, parse line and fill in a */ /* trigger structure. */ /* */ /***************************************************************/ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals) { register int r; DynamicBuffer buf; Token tok; int y, m, d; DBufInit(&buf); trig->y = NO_YR; trig->m = NO_MON; trig->d = NO_DAY; trig->wd = NO_WD; trig->back = NO_BACK; trig->delta = NO_DELTA; trig->until = NO_UNTIL; trig->rep = NO_REP; trig->localomit = NO_WD; trig->skip = NO_SKIP; trig->once = NO_ONCE; trig->typ = NO_TYPE; trig->scanfrom = NO_DATE; trig->priority = DefaultPrio; trig->sched[0] = 0; trig->warn[0] = 0; trig->omitfunc[0] = 0; DBufInit(&(trig->tags)); trig->passthru[0] = 0; tim->ttime = NO_TIME; tim->delta = NO_DELTA; tim->rep = NO_REP; tim->duration = NO_TIME; if (save_in_globals) { LastTriggerTime = NO_TIME; } while(1) { /* Read space-delimited string */ r = ParseToken(s, &buf); if (r) return r; /* Figure out what we've got */ FindToken(DBufValue(&buf), &tok); switch(tok.type) { case T_Date: DBufFree(&buf); if (trig->d != NO_DAY) return E_DAY_TWICE; if (trig->m != NO_MON) return E_MON_TWICE; if (trig->y != NO_YR) return E_YR_TWICE; FromJulian(tok.val, &y, &m, &d); trig->y = y; trig->m = m; trig->d = d; break; case T_DateTime: DBufFree(&buf); if (trig->d != NO_DAY) return E_DAY_TWICE; if (trig->m != NO_MON) return E_MON_TWICE; if (trig->y != NO_YR) return E_YR_TWICE; FromJulian(tok.val / MINUTES_PER_DAY, &y, &m, &d); trig->y = y; trig->m = m; trig->d = d; tim->ttime = (tok.val % MINUTES_PER_DAY); if (save_in_globals) { LastTriggerTime = tim->ttime; } break; case T_WkDay: DBufFree(&buf); if (trig->wd & (1 << tok.val)) return E_WD_TWICE; trig->wd |= (1 << tok.val); break; case T_Month: DBufFree(&buf); if (trig->m != NO_MON) return E_MON_TWICE; trig->m = tok.val; break; case T_Skip: DBufFree(&buf); if (trig->skip != NO_SKIP) return E_SKIP_ERR; trig->skip = tok.val; break; case T_Priority: DBufFree(&buf); r=ParsePriority(s, trig); if (r) return r; break; case T_At: DBufFree(&buf); r=ParseTimeTrig(s, tim, save_in_globals); if (r) return r; break; case T_Scanfrom: DBufFree(&buf); r=ParseScanFrom(s, trig, tok.val); if (r) return r; break; case T_RemType: DBufFree(&buf); trig->typ = tok.val; if (s->isnested) return E_CANT_NEST_RTYPE; if (trig->scanfrom == NO_DATE) trig->scanfrom = JulianToday; if (trig->typ == PASSTHRU_TYPE) { r = ParseToken(s, &buf); if (r) return r; if (!DBufLen(&buf)) { DBufFree(&buf); return E_EOLN; } StrnCpy(trig->passthru, DBufValue(&buf), PASSTHRU_LEN); } return OK; case T_Through: DBufFree(&buf); if (trig->rep != NO_REP) return E_REP_TWICE; trig->rep = 1; r = ParseUntil(s, trig); if (r) return r; break; case T_Until: DBufFree(&buf); r=ParseUntil(s, trig); if (r) return r; break; case T_Year: DBufFree(&buf); if (trig->y != NO_YR) return E_YR_TWICE; trig->y = tok.val; break; case T_Day: DBufFree(&buf); if (trig->d != NO_DAY) return E_DAY_TWICE; trig->d = tok.val; break; case T_Rep: DBufFree(&buf); if (trig->rep != NO_REP) return E_REP_TWICE; trig->rep = tok.val; break; case T_Delta: DBufFree(&buf); if (trig->delta != NO_DELTA) return E_DELTA_TWICE; trig->delta = tok.val; break; case T_Back: DBufFree(&buf); if (trig->back != NO_BACK) return E_BACK_TWICE; trig->back = tok.val; break; case T_Once: DBufFree(&buf); if (trig->once != NO_ONCE) return E_ONCE_TWICE; trig->once = ONCE_ONCE; break; case T_Omit: DBufFree(&buf); if (trig->omitfunc[0]) { Eprint("Warning: OMIT is ignored if you use OMITFUNC"); } r = ParseLocalOmit(s, trig); if (r) return r; break; case T_Empty: DBufFree(&buf); if (trig->scanfrom == NO_DATE) trig->scanfrom = JulianToday; return OK; case T_OmitFunc: if (trig->localomit) { Eprint("Warning: OMIT is ignored if you use OMITFUNC"); } r=ParseToken(s, &buf); if (r) return r; StrnCpy(trig->omitfunc, DBufValue(&buf), VAR_NAME_LEN); DBufFree(&buf); break; case T_Warn: r=ParseToken(s, &buf); if(r) return r; StrnCpy(trig->warn, DBufValue(&buf), VAR_NAME_LEN); DBufFree(&buf); break; case T_Tag: r = ParseToken(s, &buf); if (r) return r; AppendTag(&(trig->tags), DBufValue(&buf)); break; case T_Duration: r = ParseToken(s, &buf); if (r) return r; FindToken(DBufValue(&buf), &tok); DBufFree(&buf); switch(tok.type) { case T_Time: case T_LongTime: tim->duration = tok.val; break; default: return E_BAD_TIME; } break; case T_Sched: r=ParseToken(s, &buf); if(r) return r; StrnCpy(trig->sched, DBufValue(&buf), VAR_NAME_LEN); DBufFree(&buf); break; case T_LongTime: DBufFree(&buf); return E_BAD_TIME; break; default: PushToken(DBufValue(&buf), s); DBufFree(&buf); trig->typ = MSG_TYPE; if (s->isnested) return E_CANT_NEST_RTYPE; if (trig->scanfrom == NO_DATE) trig->scanfrom = JulianToday; return OK; } } } /***************************************************************/ /* */ /* ParseTimeTrig - parse the AT part of a timed reminder */ /* */ /***************************************************************/ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals) { Token tok; int r; DynamicBuffer buf; DBufInit(&buf); while(1) { r = ParseToken(s, &buf); if (r) return r; FindToken(DBufValue(&buf), &tok); switch(tok.type) { case T_Time: DBufFree(&buf); if (tim->ttime != NO_TIME) return E_TIME_TWICE; tim->ttime = tok.val; break; case T_Delta: DBufFree(&buf); if (tim->delta != NO_DELTA) return E_DELTA_TWICE; tim->delta = (tok.val > 0) ? tok.val : -tok.val; break; case T_Rep: DBufFree(&buf); if (tim->rep != NO_REP) return E_REP_TWICE; tim->rep = tok.val; break; default: if (tim->ttime == NO_TIME) return E_EXPECT_TIME; /* Save trigger time in global variable */ if (save_in_globals) { LastTriggerTime = tim->ttime; } PushToken(DBufValue(&buf), s); DBufFree(&buf); return OK; } } } /***************************************************************/ /* */ /* ParseLocalOmit - parse the local OMIT portion of a */ /* reminder. */ /* */ /***************************************************************/ static int ParseLocalOmit(ParsePtr s, Trigger *t) { Token tok; int r; DynamicBuffer buf; DBufInit(&buf); while(1) { r = ParseToken(s, &buf); if (r) return r; FindToken(DBufValue(&buf), &tok); switch(tok.type) { case T_WkDay: DBufFree(&buf); t->localomit |= (1 << tok.val); break; default: PushToken(DBufValue(&buf), s); DBufFree(&buf); return OK; } } } /***************************************************************/ /* */ /* ParseUntil - parse the UNTIL portion of a reminder */ /* */ /***************************************************************/ static int ParseUntil(ParsePtr s, Trigger *t) { int y = NO_YR, m = NO_MON, d = NO_DAY; Token tok; int r; DynamicBuffer buf; DBufInit(&buf); if (t->until != NO_UNTIL) return E_UNTIL_TWICE; while(1) { r = ParseToken(s, &buf); if (r) return r; FindToken(DBufValue(&buf), &tok); switch(tok.type) { case T_Year: DBufFree(&buf); if (y != NO_YR) { Eprint("UNTIL: %s", ErrMsg[E_YR_TWICE]); return E_YR_TWICE; } y = tok.val; break; case T_Month: DBufFree(&buf); if (m != NO_MON) { Eprint("UNTIL: %s", ErrMsg[E_MON_TWICE]); return E_MON_TWICE; } m = tok.val; break; case T_Day: DBufFree(&buf); if (d != NO_DAY) { Eprint("UNTIL: %s", ErrMsg[E_DAY_TWICE]); return E_DAY_TWICE; } d = tok.val; break; case T_Date: DBufFree(&buf); if (y != NO_YR) { Eprint("UNTIL: %s", ErrMsg[E_YR_TWICE]); return E_YR_TWICE; } if (m != NO_MON) { Eprint("UNTIL: %s", ErrMsg[E_MON_TWICE]); return E_MON_TWICE; } if (d != NO_DAY) { Eprint("UNTIL: %s", ErrMsg[E_DAY_TWICE]); return E_DAY_TWICE; } FromJulian(tok.val, &y, &m, &d); break; default: if (y == NO_YR || m == NO_MON || d == NO_DAY) { Eprint("UNTIL: %s", ErrMsg[E_INCOMPLETE]); DBufFree(&buf); return E_INCOMPLETE; } if (!DateOK(y, m, d)) { DBufFree(&buf); return E_BAD_DATE; } t->until = Julian(y, m, d); PushToken(DBufValue(&buf), s); DBufFree(&buf); return OK; } } } /***************************************************************/ /* */ /* ParseScanFrom - parse the FROM/SCANFROM portion */ /* */ /***************************************************************/ static int ParseScanFrom(ParsePtr s, Trigger *t, int type) { int y = NO_YR, m = NO_MON, d = NO_DAY; Token tok; int r; DynamicBuffer buf; char const *word; DBufInit(&buf); if (type == SCANFROM_TYPE) { word = "SCANFROM"; } else { word = "FROM"; } if (t->scanfrom != NO_DATE) return E_SCAN_TWICE; while(1) { r = ParseToken(s, &buf); if (r) return r; FindToken(DBufValue(&buf), &tok); switch(tok.type) { case T_Year: DBufFree(&buf); if (y != NO_YR) { Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]); return E_YR_TWICE; } y = tok.val; break; case T_Month: DBufFree(&buf); if (m != NO_MON) { Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]); return E_MON_TWICE; } m = tok.val; break; case T_Day: DBufFree(&buf); if (d != NO_DAY) { Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]); return E_DAY_TWICE; } d = tok.val; break; case T_Date: DBufFree(&buf); if (y != NO_YR) { Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]); return E_YR_TWICE; } if (m != NO_MON) { Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]); return E_MON_TWICE; } if (d != NO_DAY) { Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]); return E_DAY_TWICE; } FromJulian(tok.val, &y, &m, &d); break; default: if (y == NO_YR || m == NO_MON || d == NO_DAY) { Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]); DBufFree(&buf); return E_INCOMPLETE; } if (!DateOK(y, m, d)) { DBufFree(&buf); return E_BAD_DATE; } t->scanfrom = Julian(y, m, d); if (type == FROM_TYPE) { if (t->scanfrom < JulianToday) { t->scanfrom = JulianToday; } } PushToken(DBufValue(&buf), s); DBufFree(&buf); return OK; } } } /***************************************************************/ /* */ /* TriggerReminder */ /* */ /* Trigger the reminder if it's a RUN or MSG type. */ /* */ /***************************************************************/ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul) { int r, y, m, d; char PrioExpr[VAR_NAME_LEN+25]; char tmpBuf[64]; DynamicBuffer buf, calRow; DynamicBuffer pre_buf; char const *s; Value v; DBufInit(&buf); DBufInit(&calRow); DBufInit(&pre_buf); if (t->typ == RUN_TYPE && RunDisabled) return E_RUN_DISABLED; if ((t->typ == PASSTHRU_TYPE && strcmp(t->passthru, "COLOR") && strcmp(t->passthru, "COLOUR")) || t->typ == CAL_TYPE || t->typ == PS_TYPE || t->typ == PSF_TYPE) return OK; /* Handle COLOR types */ if (t->typ == PASSTHRU_TYPE && (!strcmp(t->passthru, "COLOR") || !strcmp(t->passthru, "COLOUR"))) { /* Strip off three tokens */ r = ParseToken(p, &buf); if (!NextMode) { DBufPuts(&pre_buf, DBufValue(&buf)); DBufPutc(&pre_buf, ' '); } DBufFree(&buf); if (r) return r; r = ParseToken(p, &buf); if (!NextMode) { DBufPuts(&pre_buf, DBufValue(&buf)); DBufPutc(&pre_buf, ' '); } DBufFree(&buf); if (r) return r; r = ParseToken(p, &buf); if (!NextMode) { DBufPuts(&pre_buf, DBufValue(&buf)); DBufPutc(&pre_buf, ' '); } DBufFree(&buf); if (r) return r; t->typ = MSG_TYPE; } /* If it's a MSG-type reminder, and no -k option was used, issue the banner. */ if ((t->typ == MSG_TYPE || t->typ == MSF_TYPE) && !NumTriggered && !NextMode && !MsgCommand) { if (!DoSubstFromString(DBufValue(&Banner), &buf, JulianToday, NO_TIME) && DBufLen(&buf)) { printf("%s\n", DBufValue(&buf)); } DBufFree(&buf); } /* If it's NextMode, process as a ADVANCE_MODE-type entry, and issue simple-calendar format. */ if (NextMode) { if ( (r=DoSubst(p, &buf, t, tim, jul, ADVANCE_MODE)) ) return r; if (!DBufLen(&buf)) { DBufFree(&buf); DBufFree(&pre_buf); return OK; } FromJulian(jul, &y, &m, &d); sprintf(tmpBuf, "%04d/%02d/%02d ", y, m+1, d); if (DBufPuts(&calRow, tmpBuf) != OK) { DBufFree(&calRow); DBufFree(&pre_buf); return E_NO_MEM; } /* If DoSimpleCalendar==1, output *all* simple calendar fields */ if (DoSimpleCalendar) { /* ignore passthru field when in NextMode */ if (DBufPuts(&calRow, "* ") != OK) { DBufFree(&calRow); DBufFree(&pre_buf); return E_NO_MEM; } if (*DBufValue(&(t->tags))) { DBufPuts(&calRow, DBufValue(&(t->tags))); DBufPutc(&calRow, ' '); } else { DBufPuts(&calRow, "* "); } if (tim->duration != NO_TIME) { sprintf(tmpBuf, "%d ", tim->duration); } else { sprintf(tmpBuf, "* "); } if (DBufPuts(&calRow, tmpBuf) != OK) { DBufFree(&calRow); DBufFree(&pre_buf); return E_NO_MEM; } if (tim->ttime != NO_TIME) { sprintf(tmpBuf, "%d ", tim->ttime); } else { sprintf(tmpBuf, "* "); } if (DBufPuts(&calRow, tmpBuf) != OK) { DBufFree(&calRow); DBufFree(&pre_buf); return E_NO_MEM; } } if (DBufPuts(&calRow, SimpleTime(tim->ttime)) != OK) { DBufFree(&calRow); DBufFree(&pre_buf); return E_NO_MEM; } printf("%s%s%s\n", DBufValue(&calRow), DBufValue(&pre_buf), DBufValue(&buf)); DBufFree(&buf); DBufFree(&pre_buf); DBufFree(&calRow); return OK; } /* Put the substituted string into the substitution buffer */ /* Don't use msgprefix() on RUN-type reminders */ if (t->typ != RUN_TYPE) { if (UserFuncExists("msgprefix") == 1) { sprintf(PrioExpr, "msgprefix(%d)", t->priority); s = PrioExpr; r = EvalExpr(&s, &v, NULL); if (!r) { if (!DoCoerce(STR_TYPE, &v)) { if (DBufPuts(&buf, v.v.str) != OK) { DBufFree(&buf); DestroyValue(v); return E_NO_MEM; } } DestroyValue(v); } } } if ( (r=DoSubst(p, &buf, t, tim, jul, NORMAL_MODE)) ) return r; if (t->typ != RUN_TYPE) { if (UserFuncExists("msgsuffix") == 1) { sprintf(PrioExpr, "msgsuffix(%d)", t->priority); s = PrioExpr; r = EvalExpr(&s, &v, NULL); if (!r) { if (!DoCoerce(STR_TYPE, &v)) { if (DBufPuts(&buf, v.v.str) != OK) { DBufFree(&buf); DestroyValue(v); return E_NO_MEM; } } DestroyValue(v); } } } if ((!MsgCommand && t->typ == MSG_TYPE) || t->typ == MSF_TYPE) { if (DBufPutc(&buf, '\n') != OK) { DBufFree(&buf); return E_NO_MEM; } } /* If we are sorting, just queue it up in the sort buffer */ if (SortByDate) { if (InsertIntoSortBuffer(jul, tim->ttime, DBufValue(&buf), t->typ, t->priority) == OK) { DBufFree(&buf); NumTriggered++; return OK; } } /* If we didn't insert the reminder into the sort buffer, issue the reminder now. */ switch(t->typ) { case MSG_TYPE: case PASSTHRU_TYPE: if (MsgCommand) { DoMsgCommand(MsgCommand, DBufValue(&buf)); } else { printf("%s", DBufValue(&buf)); } break; case MSF_TYPE: FillParagraph(DBufValue(&buf)); break; case RUN_TYPE: system(DBufValue(&buf)); break; default: /* Unknown/illegal type? */ DBufFree(&buf); return E_SWERR; } DBufFree(&buf); NumTriggered++; return OK; } /***************************************************************/ /* */ /* ShouldTriggerReminder */ /* */ /* Return 1 if we should trigger a reminder, based on today's */ /* date and the trigger. Return 0 if reminder should not be */ /* triggered. Sets *err non-zero in event of an error. */ /* */ /***************************************************************/ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul, int *err) { int r, omit; *err = 0; /* Handle the ONCE modifier in the reminder. */ if (!IgnoreOnce && t->once !=NO_ONCE && FileAccessDate == JulianToday) return 0; if (jul < JulianToday) return 0; /* Don't trigger timed reminders if DontIssueAts is true, and if the reminder is for today */ if (jul == JulianToday && DontIssueAts && tim->ttime != NO_TIME) { if (DontIssueAts > 1) { /* If two or more -a options, then *DO* issue ats that are in the future */ if (tim->ttime < SystemTime(0) / 60) { return 0; } } else { return 0; } } /* Don't trigger "old" timed reminders */ /*** REMOVED... if (jul == JulianToday && tim->ttime != NO_TIME && tim->ttime < SystemTime(0) / 60) return 0; *** ...UNTIL HERE */ /* If "infinite delta" option is chosen, always trigger future reminders */ if (InfiniteDelta || NextMode) return 1; /* If there's a "warn" function, it overrides any deltas */ if (t->warn[0] != 0) { if (DeltaOffset) { if (jul <= JulianToday + DeltaOffset) { return 1; } } return ShouldTriggerBasedOnWarn(t, jul, err); } /* Move back by delta days, if any */ if (t->delta != NO_DELTA) { if (t->delta < 0) jul = jul + t->delta; else { int iter = 0; int max = MaxSatIter; r = t->delta; if (max < r*2) max = r*2; while(iter++ < max) { if (!r || (jul <= JulianToday)) { break; } jul--; *err = IsOmitted(jul, t->localomit, t->omitfunc, &omit); if (*err) return 0; if (!omit) r--; } if (iter > max) { *err = E_CANT_TRIG; Eprint("Delta: Bad OMITFUNC? %s", ErrMsg[E_CANT_TRIG]); return 0; } } } /* Should we trigger the reminder? */ return (jul <= JulianToday + DeltaOffset); } /***************************************************************/ /* */ /* DoSatRemind */ /* */ /* Do the "satisfying..." remind calculation. */ /* */ /***************************************************************/ int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p) { int iter, jul, r; Value v; char const *s; char const *t; t = p->pos; iter = 0; jul = trig->scanfrom; while (iter++ < MaxSatIter) { jul = ComputeTrigger(jul, trig, &r, 1); if (r) { if (r == E_CANT_TRIG) return OK; else return r; } if (jul == -1) { return E_EXPIRED; } s = p->pos; r = EvaluateExpr(p, &v); t = p->pos; if (r) return r; if (v.type != INT_TYPE && v.type != STR_TYPE) return E_BAD_TYPE; if (v.type == INT_TYPE && v.v.val) return OK; if (v.type == STR_TYPE && *v.v.str) return OK; p->pos = s; jul++; } p->pos = t; LastTrigValid = 0; return OK; } /***************************************************************/ /* */ /* ParsePriority - parse the PRIORITY portion of a reminder */ /* */ /***************************************************************/ static int ParsePriority(ParsePtr s, Trigger *t) { int p, r; char const *u; DynamicBuffer buf; DBufInit(&buf); r = ParseToken(s, &buf); if(r) return r; u = DBufValue(&buf); if (!isdigit(*u)) { DBufFree(&buf); return E_EXPECTING_NUMBER; } p = 0; while (isdigit(*u)) { p = p*10 + *u - '0'; u++; } if (*u) { DBufFree(&buf); return E_EXPECTING_NUMBER; } DBufFree(&buf); /* Tricky! The only way p can be < 0 is if overflow occurred; thus, E2HIGH is indeed the appropriate error message. */ if (p<0 || p>9999) return E_2HIGH; t->priority = p; return OK; } /***************************************************************/ /* */ /* DoMsgCommand */ /* */ /* Execute the '-k' command, escaping shell chars in message. */ /* */ /***************************************************************/ int DoMsgCommand(char const *cmd, char const *msg) { int r; int i, l; DynamicBuffer execBuffer; DynamicBuffer buf; char const *s; DBufInit(&buf); DBufInit(&execBuffer); /* Escape shell characters in msg INCLUDING WHITESPACE! */ for (s=msg; *s; s++) { if (isspace(*s) || !strchr(DontEscapeMe, *s)) { if (DBufPutc(&buf, '\\') != OK) { r = E_NO_MEM; goto finished; } } if (DBufPutc(&buf, *s) != OK) { r = E_NO_MEM; goto finished; } } msg = DBufValue(&buf); /* Do "%s" substitution */ l = strlen(cmd); for (i=0; iwarn) != 1) { Eprint("%s: `%s'", ErrMsg[M_BAD_WARN_FUNC], t->warn); return (jul == JulianToday); } for (i=1; ; i++) { sprintf(buffer, "%s(%d)", t->warn, i); s = buffer; r = EvalExpr(&s, &v, NULL); if (r) { Eprint("%s: `%s': %s", ErrMsg[M_BAD_WARN_FUNC], t->warn, ErrMsg[r]); return (jul == JulianToday); } if (v.type != INT_TYPE) { DestroyValue(v); Eprint("%s: `%s': %s", ErrMsg[M_BAD_WARN_FUNC], t->warn, ErrMsg[E_BAD_TYPE]); return (jul == JulianToday); } /* If absolute value of return is not monotonically decreasing, exit */ if (i > 1 && abs(v.v.val) >= lastReturnVal) { return (jul == JulianToday); } lastReturnVal = abs(v.v.val); /* Positive values: Just subtract. Negative values: skip omitted days. */ if (v.v.val >= 0) { if (JulianToday + v.v.val == jul) return 1; } else { int j = jul; int iter = 0; int max = MaxSatIter; if (max < v.v.val * 2) max = v.v.val*2; while(iter++ <= max) { j--; *err = IsOmitted(j, t->localomit, t->omitfunc, &omit); if (*err) return 0; if (!omit) v.v.val++; if (!v.v.val) { break; } } if (iter > max) { Eprint("Delta: Bad OMITFUNC? %s", ErrMsg[E_CANT_TRIG]); return 0; } if (j == JulianToday) return 1; } } } remind-03.01.15/src/dosubst.c0000644000076400007640000003514612514120762013770 0ustar dfsdfs/***************************************************************/ /* */ /* DOSUBST.C */ /* */ /* This performs all the "%" substitution functions when */ /* reminders are triggered. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #define L_IN_DOSUBST #include #include #include #include #include "globals.h" #include "err.h" #include "types.h" #include "protos.h" #define UPPER(c) (islower(c) ? toupper(c) : (c)) #define ABS(x) ( (x) < 0 ? -(x) : (x) ) #ifndef NL #define NL "\n" #endif static char TODAY[] = L_TODAY; static char TOMORROW[] = L_TOMORROW; #define SHIP_OUT(s) if(DBufPuts(dbuf, s) != OK) return E_NO_MEM /***************************************************************/ /* */ /* DoSubst */ /* */ /* Process the % escapes in the reminder. If */ /* mode==NORMAL_MODE, ignore the %" sequence. If */ /* mode==CAL_MODE, process the %" sequence. */ /* If mode==ADVANCE_MODE, ignore %" but don't add newline */ /* */ /***************************************************************/ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul, int mode) { int diff = jul - JulianToday; int curtime = SystemTime(0) / 60; int err, done; int c; int d, m, y; int tim = tt->ttime; int h, min, hh, ch, cmin, chh; char const *pm, *cpm; int tdiff, adiff, mdiff, hdiff; char const *mplu, *hplu, *when, *plu; int has_quote = 0; char *ss; char *os; char s[256]; int origLen = DBufLen(dbuf); int altmode; FromJulian(jul, &y, &m, &d); if (tim == NO_TIME) tim = curtime; tdiff = tim - curtime; adiff = ABS(tdiff); mdiff = adiff % 60; hdiff = adiff / 60; #ifdef L_MPLU_OVER L_MPLU_OVER #else /* L_MPLU_OVER */ mplu = (mdiff == 1 ? "" : L_MPLU); #endif /* L_MPLU_OVER */ #ifdef L_HPLU_OVER L_HPLU_OVER #else /* L_HPLU_OVER */ hplu = (hdiff == 1 ? "" : L_HPLU); #endif /* L_HPLU_OVER */ when = (tdiff < 0 ? L_AGO : L_FROMNOW); h = tim / 60; min = tim % 60; #ifdef L_AMPM_OVERRIDE L_AMPM_OVERRIDE (pm, h) #else pm = (h < 12) ? L_AM : L_PM; #endif hh = (h == 12) ? 12 : h % 12; ch = curtime / 60; cmin = curtime % 60; #ifdef L_AMPM_OVERRIDE L_AMPM_OVERRIDE (cpm, ch) #else cpm = (ch < 12) ? L_AM : L_PM; #endif chh = (ch == 12) ? 12 : ch % 12; #ifdef L_ORDINAL_OVERRIDE L_ORDINAL_OVERRIDE #else switch(d) { case 1: case 21: case 31: plu = "st"; break; case 2: case 22: plu = "nd"; break; case 3: case 23: plu = "rd"; break; default: plu = "th"; break; } #endif while(1) { c = ParseChar(p, &err, 0); if (err) { DBufFree(dbuf); return err; } if (c == '\n') continue; if (!c) { if (mode != CAL_MODE && mode != ADVANCE_MODE && t->typ != RUN_TYPE && !MsgCommand) { if (DBufPutc(dbuf, '\n') != OK) return E_NO_MEM; } break; } if (c != '%') { if (DBufPutc(dbuf, c) != OK) return E_NO_MEM; continue; } altmode = 0; s[0] = 0; c = ParseChar(p, &err, 0); if (err) { DBufFree(dbuf); return err; } if (!c) { break; } if (c == '*') { altmode = c; c = ParseChar(p, &err, 0); if (err) { DBufFree(dbuf); return err; } if (!c) { break; } } done = 0; if (diff <= 1) { switch(UPPER(c)) { #ifndef L_NOTOMORROW_A case 'A': #endif #ifndef L_NOTOMORROW_B case 'B': #endif #ifndef L_NOTOMORROW_C case 'C': #endif #ifndef L_NOTOMORROW_E case 'E': #endif #ifndef L_NOTOMORROW_F case 'F': #endif #ifndef L_NOTOMORROW_G case 'G': #endif #ifndef L_NOTOMORROW_H case 'H': #endif #ifndef L_NOTOMORROW_I case 'I': #endif #ifndef L_NOTOMORROW_J case 'J': #endif #ifndef L_NOTOMORROW_K case 'K': #endif #ifndef L_NOTOMORROW_L case 'L': #endif #ifndef L_NOTOMORROW_U case 'U': #endif #ifndef L_NOTOMORROW_V case 'V': #endif sprintf(s, "%s", (diff ? TOMORROW : TODAY)); SHIP_OUT(s); done = 1; break; default: done = 0; } } if (!done) switch(UPPER(c)) { case 'A': #ifdef L_A_OVER L_A_OVER #else if (altmode == '*') { sprintf(s, "%s, %d %s, %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, %d %s, %d", L_ON, DayName[jul%7], d, MonthName[m], y); } #endif SHIP_OUT(s); break; case 'B': #ifdef L_B_OVER L_B_OVER #else sprintf(s, L_INXDAYS, diff); #endif SHIP_OUT(s); break; case 'C': #ifdef L_C_OVER L_C_OVER #else if (altmode == '*') { sprintf(s, "%s", DayName[jul%7]); } else { sprintf(s, "%s %s", L_ON, DayName[jul%7]); } #endif SHIP_OUT(s); break; case 'D': #ifdef L_D_OVER L_D_OVER #else sprintf(s, "%d", d); #endif SHIP_OUT(s); break; case 'E': #ifdef L_E_OVER L_E_OVER #else if (altmode == '*') { sprintf(s, "%02d%c%02d%c%04d", d, DateSep, m+1, DateSep, y); } else { sprintf(s, "%s %02d%c%02d%c%04d", L_ON, d, DateSep, m+1, DateSep, y); } #endif SHIP_OUT(s); break; case 'F': #ifdef L_F_OVER L_F_OVER #else if (altmode == '*') { sprintf(s, "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y); } else { sprintf(s, "%s %02d%c%02d%c%04d", L_ON, m+1, DateSep, d, DateSep, y); } #endif SHIP_OUT(s); break; case 'G': #ifdef L_G_OVER L_G_OVER #else if (altmode == '*') { sprintf(s, "%s, %d %s", DayName[jul%7], d, MonthName[m]); } else { sprintf(s, "%s %s, %d %s", L_ON, DayName[jul%7], d, MonthName[m]); } #endif SHIP_OUT(s); break; case 'H': #ifdef L_H_OVER L_H_OVER #else if (altmode == '*') { sprintf(s, "%02d%c%02d", d, DateSep, m+1); } else { sprintf(s, "%s %02d%c%02d", L_ON, d, DateSep, m+1); } #endif SHIP_OUT(s); break; case 'I': #ifdef L_I_OVER L_I_OVER #else if (altmode == '*') { sprintf(s, "%02d%c%02d", m+1, DateSep, d); } else { sprintf(s, "%s %02d%c%02d", L_ON, m+1, DateSep, d); } #endif SHIP_OUT(s); break; case 'J': #ifdef L_J_OVER L_J_OVER #else if (altmode == '*') { sprintf(s, "%s, %s %d%s, %d", DayName[jul%7], MonthName[m], d, plu, y); } else { sprintf(s, "%s %s, %s %d%s, %d", L_ON, DayName[jul%7], MonthName[m], d, plu, y); } #endif SHIP_OUT(s); break; case 'K': #ifdef L_K_OVER L_K_OVER #else if (altmode == '*') { sprintf(s, "%s, %s %d%s", DayName[jul%7], MonthName[m], d, plu); } else { sprintf(s, "%s %s, %s %d%s", L_ON, DayName[jul%7], MonthName[m], d, plu); } #endif SHIP_OUT(s); break; case 'L': #ifdef L_L_OVER L_L_OVER #else if (altmode == '*') { sprintf(s, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d); } else { sprintf(s, "%s %04d%c%02d%c%02d", L_ON, y, DateSep, m+1, DateSep, d); } #endif SHIP_OUT(s); break; case 'M': #ifdef L_M_OVER L_M_OVER #else sprintf(s, "%s", MonthName[m]); #endif SHIP_OUT(s); break; case 'N': #ifdef L_N_OVER L_N_OVER #else sprintf(s, "%d", m+1); #endif SHIP_OUT(s); break; case 'O': #ifdef L_O_OVER L_O_OVER #else if (RealToday == JulianToday) sprintf(s, " (%s)", L_TODAY); else *s = 0; #endif SHIP_OUT(s); break; case 'P': #ifdef L_P_OVER L_P_OVER #else sprintf(s, "%s", (diff == 1 ? "" : L_PLURAL)); #endif SHIP_OUT(s); break; case 'Q': #ifdef L_Q_OVER L_Q_OVER #else sprintf(s, "%s", (diff == 1 ? "'s" : "s'")); #endif SHIP_OUT(s); break; case 'R': #ifdef L_R_OVER L_R_OVER #else sprintf(s, "%02d", d); #endif SHIP_OUT(s); break; case 'S': #ifdef L_S_OVER L_S_OVER #else sprintf(s, "%s", plu); #endif SHIP_OUT(s); break; case 'T': #ifdef L_T_OVER L_T_OVER #else sprintf(s, "%02d", m+1); #endif SHIP_OUT(s); break; case 'U': #ifdef L_U_OVER L_U_OVER #else if (altmode == '*') { sprintf(s, "%s, %d%s %s, %d", DayName[jul%7], d, plu, MonthName[m], y); } else { sprintf(s, "%s %s, %d%s %s, %d", L_ON, DayName[jul%7], d, plu, MonthName[m], y); } #endif SHIP_OUT(s); break; case 'V': #ifdef L_V_OVER L_V_OVER #else if (altmode == '*') { sprintf(s, "%s, %d%s %s", DayName[jul%7], d, plu, MonthName[m]); } else { sprintf(s, "%s %s, %d%s %s", L_ON, DayName[jul%7], d, plu, MonthName[m]); } #endif SHIP_OUT(s); break; case 'W': #ifdef L_W_OVER L_W_OVER #else sprintf(s, "%s", DayName[jul%7]); #endif SHIP_OUT(s); break; case 'X': #ifdef L_X_OVER L_X_OVER #else sprintf(s, "%d", diff); #endif SHIP_OUT(s); break; case 'Y': #ifdef L_Y_OVER L_Y_OVER #else sprintf(s, "%d", y); #endif SHIP_OUT(s); break; case 'Z': #ifdef L_Z_OVER L_Z_OVER #else sprintf(s, "%d", y % 100); #endif SHIP_OUT(s); break; case '1': #ifdef L_1_OVER L_1_OVER #else if (tdiff == 0) sprintf(s, "%s", L_NOW); else if (hdiff == 0) sprintf(s, "%d %s%s %s", mdiff, L_MINUTE, mplu, when); else if (mdiff == 0) sprintf(s, "%d %s%s %s", hdiff, L_HOUR, hplu, when); else sprintf(s, "%d %s%s %s %d %s%s %s", hdiff, L_HOUR, hplu, L_AND, mdiff, L_MINUTE, mplu, when); #endif SHIP_OUT(s); break; case '2': #ifdef L_2_OVER L_2_OVER #else if (altmode == '*') { sprintf(s, "%d%c%02d%s", hh, TimeSep, min, pm); } else { sprintf(s, "%s %d%c%02d%s", L_AT, hh, TimeSep, min, pm); } #endif SHIP_OUT(s); break; case '3': #ifdef L_3_OVER L_3_OVER #else if (altmode == '*') { sprintf(s, "%02d%c%02d", h, TimeSep, min); } else { sprintf(s, "%s %02d%c%02d", L_AT, h, TimeSep, min); } #endif SHIP_OUT(s); break; case '4': #ifdef L_4_OVER L_4_OVER #else sprintf(s, "%d", tdiff); #endif SHIP_OUT(s); break; case '5': #ifdef L_5_OVER L_5_OVER #else sprintf(s, "%d", adiff); #endif SHIP_OUT(s); break; case '6': #ifdef L_6_OVER L_6_OVER #else sprintf(s, "%s", when); #endif SHIP_OUT(s); break; case '7': #ifdef L_7_OVER L_7_OVER #else sprintf(s, "%d", hdiff); #endif SHIP_OUT(s); break; case '8': #ifdef L_8_OVER L_8_OVER #else sprintf(s, "%d", mdiff); #endif SHIP_OUT(s); break; case '9': #ifdef L_9_OVER L_9_OVER #else sprintf(s, "%s", mplu); #endif SHIP_OUT(s); break; case '0': #ifdef L_0_OVER L_0_OVER #else sprintf(s, "%s", hplu); #endif SHIP_OUT(s); break; case '!': #ifdef L_BANG_OVER L_BANG_OVER #else sprintf(s, "%s", (tdiff >= 0 ? L_IS : L_WAS)); #endif SHIP_OUT(s); break; case '@': #ifdef L_AT_OVER L_AT_OVER #else sprintf(s, "%d%c%02d%s", chh, TimeSep, cmin, cpm); #endif SHIP_OUT(s); break; case '#': #ifdef L_HASH_OVER L_HASH_OVER #else sprintf(s, "%02d%c%02d", ch, TimeSep, cmin); #endif SHIP_OUT(s); break; case '_': if (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand) sprintf(s, "%s", NL); else sprintf(s, " "); SHIP_OUT(s); break; case QUOTE_MARKER: /* Swallow any QUOTE_MARKERs which may somehow creep in... */ break; case '"': if (DBufPutc(dbuf, QUOTE_MARKER) != OK) return E_NO_MEM; has_quote = 1; break; default: if (DBufPutc(dbuf, c) != OK) return E_NO_MEM; } if (isupper(c)) { os = DBufValue(dbuf); os += strlen(os) - strlen(s); if (os >= DBufValue(dbuf)) { *os = UPPER(*os); } } } /* We're outside the big while loop. The only way to get here is for c to be null. Now we go through and delete %" sequences, if it's the NORMAL_MODE, or retain only things within a %" sequence if it's the CAL_MODE. */ /* If there are NO quotes, then: If CAL_MODE && RUN_TYPE, we don't want the reminder in the calendar. Zero the output buffer and quit. */ if (!has_quote) { if ((mode == ADVANCE_MODE || mode == CAL_MODE) && t->typ == RUN_TYPE) { *DBufValue(dbuf) = 0; dbuf->len = 0; } return OK; } /* There ARE quotes. If in CAL_MODE, delete everything before first quote and after second quote. If in NORMAL_MODE, delete the %" sequences. */ ss = DBufValue(dbuf) + origLen; os = ss; if (mode == NORMAL_MODE || mode == ADVANCE_MODE) { while (*ss) { if (*ss != QUOTE_MARKER) *os++ = *ss; ss++; } *os = 0; } else { /* Skip past the quote marker */ while (*ss && (*ss != QUOTE_MARKER)) ss++; /* Security check... actually, *s must == QUOTE_MARKER at this point, but it doesn't hurt to make it a bit robust. */ if (*ss) ss++; /* Copy the output until the next QUOTE_MARKER */ while (*ss && (*ss != QUOTE_MARKER)) *os++ = *ss++; *os = 0; } /* Violating encapsulation here!!!! */ dbuf->len = strlen(dbuf->buffer); return OK; } /***************************************************************/ /* */ /* DoSubstFromString */ /* */ /* DoSubst consumes input from a parser. This function */ /* consumes characters from a string. It also provides */ /* default triggers and a mode of NORMAL_MODE. */ /* */ /***************************************************************/ int DoSubstFromString(char const *source, DynamicBuffer *dbuf, int jul, int tim) { Trigger tempTrig; TimeTrig tempTime; Parser tempP; int r; if (jul == NO_DATE) jul=JulianToday; if (tim == NO_TIME) tim=SystemTime(0)/60; CreateParser(source, &tempP); tempP.allownested = 0; tempTrig.typ = MSG_TYPE; tempTime.ttime = tim; r = DoSubst(&tempP, dbuf, &tempTrig, &tempTime, jul, NORMAL_MODE); DestroyParser(&tempP); return r; } remind-03.01.15/src/dynbuf.c0000644000076400007640000001172312514120757013573 0ustar dfsdfs/***************************************************************/ /* */ /* DYNBUF.C */ /* */ /* Implementation of functions for manipulating dynamic */ /* buffers. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include "dynbuf.h" #include "err.h" #include #include /********************************************************************** %FUNCTION: DBufMakeRoom %ARGUMENTS: dbuf -- pointer to a dynamic buffer n -- size to expand to %RETURNS: OK if all went well; E_NO_MEM if out of memory %DESCRIPTION: Doubles the size of dynamic buffer until it has room for at least 'n' characters, not including trailing '\0' **********************************************************************/ static int DBufMakeRoom(DynamicBuffer *dbuf, int n) { /* Double size until it's greater than n (strictly > to leave room for trailing '\0' */ int size = dbuf->allocatedLen; char *buf; if (size > n) return OK; while (size <= n) { size *= 2; } /* Allocate memory */ buf = malloc(size); if (!buf) return E_NO_MEM; /* Copy contents */ strcpy(buf, dbuf->buffer); /* Free contents if necessary */ if (dbuf->buffer != dbuf->staticBuf) free(dbuf->buffer); dbuf->buffer = buf; dbuf->allocatedLen = size; return OK; } /********************************************************************** %FUNCTION: DBufInit %ARGUMENTS: dbuf -- pointer to a dynamic buffer %RETURNS: Nothing %DESCRIPTION: Initializes a dynamic buffer **********************************************************************/ void DBufInit(DynamicBuffer *dbuf) { dbuf->buffer = dbuf->staticBuf; dbuf->len = 0; dbuf->allocatedLen = DBUF_STATIC_SIZE; dbuf->buffer[0] = 0; } /********************************************************************** %FUNCTION: DBufPutcFN %ARGUMENTS: dbuf -- pointer to a dynamic buffer c -- character to append to buffer %RETURNS: OK if all went well; E_NO_MEM if out of memory %DESCRIPTION: Appends a character to the buffer. **********************************************************************/ int DBufPutcFN(DynamicBuffer *dbuf, char c) { if (dbuf->allocatedLen == dbuf->len+1) { if (DBufMakeRoom(dbuf, dbuf->len+1) != OK) return E_NO_MEM; } dbuf->buffer[dbuf->len++] = c; dbuf->buffer[dbuf->len] = 0; return OK; } /********************************************************************** %FUNCTION: DBufPuts %ARGUMENTS: dbuf -- pointer to a dynamic buffer str -- string to append to buffer %RETURNS: OK if all went well; E_NO_MEM if out of memory %DESCRIPTION: Appends a string to the buffer. **********************************************************************/ int DBufPuts(DynamicBuffer *dbuf, char const *str) { int l = strlen(str); if (!l) return OK; if (DBufMakeRoom(dbuf, dbuf->len+l) != OK) return E_NO_MEM; strcpy((dbuf->buffer+dbuf->len), str); dbuf->len += l; return OK; } /********************************************************************** %FUNCTION: DBufFree %ARGUMENTS: dbuf -- pointer to a dynamic buffer %RETURNS: Nothing %DESCRIPTION: Frees and reinitializes a dynamic buffer **********************************************************************/ void DBufFree(DynamicBuffer *dbuf) { if (dbuf->buffer != dbuf->staticBuf) free(dbuf->buffer); DBufInit(dbuf); } /********************************************************************** %FUNCTION: DBufGets %ARGUMENTS: dbuf -- pointer to a dynamic buffer fp -- file to read from %RETURNS: OK or E_NO_MEM %DESCRIPTION: Reads an entire line from a file and appends to dbuf. Does not include trailing newline. **********************************************************************/ int DBufGets(DynamicBuffer *dbuf, FILE *fp) { char tmp[256]; /* Safe to hard-code */ int busy = 1; int l; DBufFree(dbuf); /* Try reading the first few bytes right into the buffer -- we can usually save some unnecessary copying */ *(dbuf->buffer) = 0; fgets(dbuf->buffer, dbuf->allocatedLen, fp); if (!*(dbuf->buffer)) return OK; dbuf->len = strlen(dbuf->buffer); l = dbuf->len - 1; if (dbuf->buffer[l] == '\n') { dbuf->buffer[l] = 0; dbuf->len = l; return OK; } while(busy) { *tmp = 0; fgets(tmp, 256, fp); if (!*tmp) return OK; l = strlen(tmp) - 1; if (tmp[l] == '\n') { tmp[l] = 0; busy = 0; } if (DBufPuts(dbuf, tmp) != OK) return E_NO_MEM; } return OK; } remind-03.01.15/src/dynbuf.h0000644000076400007640000000264112514120753013573 0ustar dfsdfs/***************************************************************/ /* */ /* DYNBUF.H */ /* */ /* Declaration of functions for manipulating dynamic buffers */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #ifndef DYNBUF_H #define DYNBUF_H #include /* For FILE */ #define DBUF_STATIC_SIZE 128 typedef struct { char *buffer; int len; int allocatedLen; char staticBuf[DBUF_STATIC_SIZE]; } DynamicBuffer; void DBufInit(DynamicBuffer *dbuf); int DBufPutcFN(DynamicBuffer *dbuf, char c); int DBufPuts(DynamicBuffer *dbuf, char const *str); void DBufFree(DynamicBuffer *dbuf); int DBufGets(DynamicBuffer *dbuf, FILE *fp); #define DBufValue(bufPtr) ((bufPtr)->buffer) #define DBufLen(bufPtr) ((bufPtr)->len) #define DBufPutc(dbuf, c) ( (dbuf)->allocatedLen < (dbuf)->len+1 ) ? (dbuf)->buffer[(dbuf)->len++] = c, (dbuf)->buffer[(dbuf)->len] = 0, OK : DBufPutcFN((dbuf), c) #endif /* DYNBUF_H */ remind-03.01.15/src/err.h0000644000076400007640000001673012531375322013103 0ustar dfsdfs/***************************************************************/ /* */ /* ERR.H */ /* */ /* Error definitions. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* Note that not all of the "errors" are really errors - some are just messages for information purposes. Constants beginning with M_ should never be returned as error indicators - they should only be used to index the ErrMsg array. */ #define OK 0 #define E_MISS_END 1 #define E_MISS_QUOTE 2 #define E_OP_STK_OVER 3 #define E_VA_STK_OVER 4 #define E_MISS_RIGHT_PAREN 5 #define E_UNDEF_FUNC 6 #define E_ILLEGAL_CHAR 7 #define E_EXPECTING_BINOP 8 #define E_NO_MEM 9 #define E_BAD_NUMBER 10 #define E_OP_STK_UNDER 11 #define E_VA_STK_UNDER 12 #define E_CANT_COERCE 13 #define E_BAD_TYPE 14 #define E_DATE_OVER 15 #define E_STACK_ERR 16 #define E_DIV_ZERO 17 #define E_NOSUCH_VAR 18 #define E_EOLN 19 #define E_EOF 20 #define E_IO_ERR 21 #define E_LINE_2_LONG 22 #define E_SWERR 23 #define E_BAD_DATE 24 #define E_2FEW_ARGS 25 #define E_2MANY_ARGS 26 #define E_BAD_TIME 27 #define E_2HIGH 28 #define E_2LOW 29 #define E_CANT_OPEN 30 #define E_NESTED_INCLUDE 31 #define E_PARSE_ERR 32 #define E_CANT_TRIG 33 #define E_NESTED_IF 34 #define E_ELSE_NO_IF 35 #define E_ENDIF_NO_IF 36 #define E_2MANY_LOCALOMIT 37 #define E_EXTRANEOUS_TOKEN 38 #define E_POP_NO_PUSH 39 #define E_RUN_DISABLED 40 #define E_DOMAIN_ERR 41 #define E_BAD_ID 42 #define E_RECURSIVE 43 #define E_PARSE_AS_REM 44 /* Not really an error - just returned by DoOmit to indicate line should be executed as a REM statement, also. */ #define E_CANT_MODIFY 45 #define E_MKTIME_PROBLEM 46 #define E_REDEF_FUNC 47 #define E_CANTNEST_FDEF 48 #define E_REP_FULSPEC 49 #define E_YR_TWICE 50 #define E_MON_TWICE 51 #define E_DAY_TWICE 52 #define E_UNKNOWN_TOKEN 53 #define E_SPEC_MON_DAY 54 #define E_2MANY_PART 55 #define E_2MANY_FULL 56 #define E_PUSH_NOPOP 57 #define E_ERR_READING 58 #define E_EXPECTING_EOL 59 #define E_BAD_HEBDATE 60 #define E_IIF_ODD 61 #define E_MISS_ENDIF 62 #define E_EXPECT_COMMA 63 #define E_WD_TWICE 64 #define E_SKIP_ERR 65 #define E_CANT_NEST_RTYPE 66 #define E_REP_TWICE 67 #define E_DELTA_TWICE 68 #define E_BACK_TWICE 69 #define E_ONCE_TWICE 70 #define E_EXPECT_TIME 71 #define E_UNTIL_TWICE 72 #define E_INCOMPLETE 73 #define E_SCAN_TWICE 74 #define E_VAR 75 #define E_VAL 76 #define E_UNDEF 77 #define E_ENTER_FUN 78 #define E_LEAVE_FUN 79 #define E_EXPIRED 80 #define E_CANTFORK 81 #define E_CANTACCESS 82 #define M_BAD_SYS_DATE 83 #define M_BAD_DB_FLAG 84 #define M_BAD_OPTION 85 #define M_BAD_USER 86 #define M_NO_CHG_GID 87 #define M_NO_CHG_UID 88 #define M_NOMEM_ENV 89 #define E_MISS_EQ 90 #define E_MISS_VAR 91 #define E_MISS_EXPR 92 #define M_CANTSET_ACCESS 93 #define M_I_OPTION 94 #define E_NOREMINDERS 95 #define M_QUEUED 96 #define E_EXPECTING_NUMBER 97 #define M_BAD_WARN_FUNC 98 #define E_CANT_CONVERT_TZ 99 #define E_NO_MATCHING_REMS 100 #define E_STRING_TOO_LONG 101 #define E_TIME_TWICE 102 #ifdef MK_GLOBALS #undef EXTERN #define EXTERN #else #undef EXTERN #define EXTERN extern #endif #ifndef L_ERR_OVERRIDE EXTERN char *ErrMsg[] #ifdef MK_GLOBALS = { "Ok", "Missing ']'", "Missing quote", "Expression too complex - too many operators", "Expression too complex - too many operands", "Missing ')'", "Undefined function", "Illegal character", "Expecting binary operator", "Out of memory", "Ill-formed number", "Op stack underflow - internal error", "Va stack underflow - internal error", "Can't coerce", "Type mismatch", "Date overflow", "Stack error - internal error", "Division by zero", "Undefined variable", "Unexpected end of line", "Unexpected end of file", "I/O error", "Line too long", "Internal error", "Bad date specification", "Not enough arguments", "Too many arguments", "Ill-formed time", "Number too high", "Number too low", "Can't open file", "INCLUDE nested too deeply", "Parse error", "Can't compute trigger", "Too many nested IFs", "ELSE with no matching IF", "ENDIF with no matching IF", "Can't OMIT every weekday", "Extraneous token(s) on line", "POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT", "RUN disabled", "Domain error", "Invalid identifier", "Recursive function call detected", "", "Cannot modify system variable", "C library function can't represent date/time", "Attempt to redefine built-in function", "Can't nest function definition in expression", "Must fully specify date to use repeat factor", "Year specified twice", "Month specified twice", "Day specified twice", "Unknown token", "Must specify month and day in OMIT command", "Too many partial OMITs", "Too many full OMITs", "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT", "Error reading", "Expecting end-of-line", "Invalid Hebrew date", "IIF needs odd number of arguments", "Warning: Missing ENDIF", "Expecting comma", "Weekday specified twice", "Only use one of BEFORE, AFTER or SKIP", "Can't nest MSG, MSF, RUN, etc. in expression", "Repeat value specified twice", "Delta value specified twice", "Back value specified twice", "ONCE keyword used twice. (Hah.)", "Expecting time after AT", "THROUGH/UNTIL keyword used twice", "Incomplete date specification", "FROM/SCANFROM keyword used twice", "Variable", "Value", "*UNDEFINED*", "Entering UserFN", "Leaving UserFN", "Expired", "fork() failed - can't do queued reminders", "Can't access file", "Illegal system date: Year is less than %d\n", "Unknown debug flag '%c'\n", "Unknown option '%c'\n", "Unknown user '%s'\n", "Could not change gid to %d\n", "Could not change uid to %d\n", "Out of memory for environment\n", "Missing '=' sign", "Missing variable name", "Missing expression", "Can't reset access date of %s\n", "Remind: '-i' option: %s\n", "No reminders.", "%d reminder(s) queued for later today.\n", "Expecting number", "Bad function in WARN clause", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" } #endif /* MK_GLOBALS */ ; #endif /* L_ERR_OVERRIDE */ remind-03.01.15/src/expr.c0000644000076400007640000011053112514120736013254 0ustar dfsdfs/***************************************************************/ /* */ /* EXPR.C */ /* */ /* This file contains routines to parse and evaluate */ /* expressions. */ /* */ /* Copyright 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #include "err.h" #include "types.h" #include "expr.h" #include "protos.h" #include "globals.h" #define ISID(c) (isalnum(c) || (c) == '_') #define EQ 0 #define GT 1 #define LT 2 #define GE 3 #define LE 4 #define NE 5 static char CoerceBuf[512]; extern int NumFuncs; static int Multiply(void), Divide(void), Mod(void), Add(void), Subtract(void), GreaterThan(void), LessThan(void), EqualTo(void), NotEqual(void), LessOrEqual(void), GreaterOrEqual(void), LogAND(void), LogOR(void), UnMinus(void), LogNot(void), Compare(int); static int MakeValue (char const *s, Value *v, Var *locals, ParsePtr p); /* Binary operators - all left-associative */ /* Make SURE they are sorted lexically... this may die on an EBCDIC system... */ Operator BinOp[] = { { "!=", 15, BIN_OP, NotEqual }, { "%", 20, BIN_OP, Mod }, { "&&", 14, BIN_OP, LogAND }, { "*", 20, BIN_OP, Multiply }, { "+", 18, BIN_OP, Add }, { "-", 18, BIN_OP, Subtract }, { "/", 20, BIN_OP, Divide }, { "<", 16, BIN_OP, LessThan }, { "<=", 16, BIN_OP, LessOrEqual }, { "==", 15, BIN_OP, EqualTo }, { ">", 16, BIN_OP, GreaterThan }, { ">=", 16, BIN_OP, GreaterOrEqual }, { "||", 12, BIN_OP, LogOR }, }; #define NUM_BIN_OPS (sizeof(BinOp) / sizeof(Operator)) /* These ones must be sorted too. */ Operator UnOp[] = { { "!", 22, UN_OP, LogNot }, { "-", 22, UN_OP, UnMinus }, }; #define NUM_UN_OPS (sizeof(UnOp) / sizeof(Operator)) extern BuiltinFunc Func[]; Operator OpStack[OP_STACK_SIZE]; Value ValStack[VAL_STACK_SIZE]; int OpStackPtr, ValStackPtr; /***************************************************************/ /* */ /* DebugPerform */ /* */ /* Execute an operator or function with debugging. */ /* */ /***************************************************************/ static int DebugPerform(Operator *op) { int r; if (op->type == UN_OP) { fprintf(ErrFp, "%s ", op->name); PrintValue(&ValStack[ValStackPtr-1], ErrFp); } else { /* Must be binary operator */ PrintValue(&ValStack[ValStackPtr-2], ErrFp); fprintf(ErrFp, " %s ", op->name); PrintValue(&ValStack[ValStackPtr-1], ErrFp); } r = (op->func)(); fprintf(ErrFp, " => "); if (!r) { PrintValue(&ValStack[ValStackPtr-1], ErrFp); Putc('\n', ErrFp); } else { fprintf(ErrFp, "%s\n", ErrMsg[r]); } return r; } /***************************************************************/ /* */ /* CleanStack */ /* */ /* Clean the stack after an error occurs. */ /* */ /***************************************************************/ static void CleanStack(void) { int i; for (i=0; i': case '<': if (**in == '=') { if (DBufPutc(buf, '=') != OK) { DBufFree(buf); return E_NO_MEM; } (*in)++; } return OK; } /* Handle the parsing of quoted strings */ if (c == '\"') { if (!**in) return E_MISS_QUOTE; while (**in) { /* Allow backslash-escapes */ if (**in == '\\') { int r; (*in)++; if (!**in) { DBufFree(buf); return E_MISS_QUOTE; } switch(**in) { case 'a': r = DBufPutc(buf, '\a'); break; case 'b': r = DBufPutc(buf, '\b'); break; case 'f': r = DBufPutc(buf, '\f'); break; case 'n': r = DBufPutc(buf, '\n'); break; case 'r': r = DBufPutc(buf, '\r'); break; case 't': r = DBufPutc(buf, '\t'); break; case 'v': r = DBufPutc(buf, '\v'); break; default: r = DBufPutc(buf, **in); } (*in)++; if (r != OK) { DBufFree(buf); return E_NO_MEM; } continue; } c = *(*in)++; if (DBufPutc(buf, c) != OK) { DBufFree(buf); return E_NO_MEM; } if (c == '\"') break; } if (c == '\"') return OK; DBufFree(buf); return E_MISS_QUOTE; } /* Dates can be specified with single-quotes */ if (c == '\'') { if (!**in) return E_MISS_QUOTE; while (**in) { c = *(*in)++; if (DBufPutc(buf, c) != OK) { DBufFree(buf); return E_NO_MEM; } if (c == '\'') break; } if (c == '\'') return OK; DBufFree(buf); return E_MISS_QUOTE; } if (!ISID(c) && c != '$') { Eprint("%s `%c'", ErrMsg[E_ILLEGAL_CHAR], c); return E_ILLEGAL_CHAR; } /* Parse a constant, variable name or function */ while (ISID(**in) || **in == ':' || **in == '.' || **in == TimeSep) { if (DBufPutc(buf, **in) != OK) { DBufFree(buf); return E_NO_MEM; } (*in)++; } /* Chew up any remaining white space */ while (**in && isempty(**in)) (*in)++; /* Peek ahead - is it '('? Then we have a function call */ if (**in == '(') { if (DBufPutc(buf, '(') != OK) { DBufFree(buf); return E_NO_MEM; } (*in)++; } return OK; } /***************************************************************/ /* */ /* EvalExpr */ /* Evaluate an expression. Return 0 if OK, non-zero if error */ /* Put the result into value pointed to by v. */ /* */ /***************************************************************/ int EvalExpr(char const **e, Value *v, ParsePtr p) { int r; OpStackPtr = 0; ValStackPtr = 0; r = Evaluate(e, NULL, p); /* Put last character parsed back onto input stream */ if (DBufLen(&ExprBuf)) (*e)--; DBufFree(&ExprBuf); if (r) { CleanStack(); return r; } *v = *ValStack; ValStack[0].type = ERR_TYPE; return r; } /* Evaluate - do the actual work of evaluation. */ int Evaluate(char const **s, Var *locals, ParsePtr p) { int OpBase, ValBase; int r; Operator *o; BuiltinFunc *f; int args; /* Number of function arguments */ Operator op, op2; Value va; char const *ufname = NULL; /* Stop GCC from complaining about use of uninit var */ OpBase = OpStackPtr; ValBase = ValStackPtr; while(1) { /* Looking for a value. Accept: value, unary op, func. call or left paren */ r = ParseExprToken(&ExprBuf, s); if (r) return r; if (!DBufLen(&ExprBuf)) { DBufFree(&ExprBuf); return E_EOLN; } if (*DBufValue(&ExprBuf) == '(') { /* Parenthesized expression */ DBufFree(&ExprBuf); r = Evaluate(s, locals, p); /* Leaves the last parsed token in ExprBuf */ if (r) return r; r = OK; if (*DBufValue(&ExprBuf) != ')') { DBufFree(&ExprBuf); return E_MISS_RIGHT_PAREN; } if (r) return r; } else if (*DBufValue(&ExprBuf) == '+') { continue; /* Ignore unary + */ } else if (*(DBufValue(&ExprBuf) + DBufLen(&ExprBuf) -1) == '(') { /* Function Call */ *(DBufValue(&ExprBuf) + DBufLen(&ExprBuf) - 1) = 0; f = FindFunc(DBufValue(&ExprBuf), Func, NumFuncs); if (!f) { ufname = StrDup(DBufValue(&ExprBuf)); DBufFree(&ExprBuf); if (!ufname) return E_NO_MEM; } else { DBufFree(&ExprBuf); } args = 0; if (PeekChar(s) == ')') { /* Function has no arguments */ if (f) { if (!f->is_constant && (p != NULL)) p->nonconst_expr = 1; r = CallFunc(f, 0); } else { r = CallUserFunc(ufname, 0, p); free((char *) ufname); } if (r) return r; r = ParseExprToken(&ExprBuf, s); /* Guaranteed to be right paren. */ if (r) return r; } else { /* Function has some arguments */ while(1) { args++; r = Evaluate(s, locals, p); if (r) { if (!f) free((char *) ufname); return r; } if (*DBufValue(&ExprBuf) == ')') break; else if (*DBufValue(&ExprBuf) != ',') { if (!f) free((char *) ufname); Eprint("%s: `%c'", ErrMsg[E_EXPECT_COMMA], *DBufValue(&ExprBuf)); DBufFree(&ExprBuf); return E_EXPECT_COMMA; } } if (f) { if (!f->is_constant && (p != NULL)) p->nonconst_expr = 1; r = CallFunc(f, args); } else { r = CallUserFunc(ufname, args, p); free((char *) ufname); } DBufFree(&ExprBuf); if (r) return r; } } else { /* Unary operator */ o = FindOperator(DBufValue(&ExprBuf), UnOp, NUM_UN_OPS); if (o) { DBufFree(&ExprBuf); PushOpStack(*o); continue; /* Still looking for an atomic vlue */ } else if (!ISID(*DBufValue(&ExprBuf)) && *DBufValue(&ExprBuf) != '$' && *DBufValue(&ExprBuf) != '"' && *DBufValue(&ExprBuf) != '\'') { Eprint("%s `%c'", ErrMsg[E_ILLEGAL_CHAR], *DBufValue(&ExprBuf)); DBufFree(&ExprBuf); return E_ILLEGAL_CHAR; } else { /* Must be a literal value */ r = MakeValue(DBufValue(&ExprBuf), &va, locals, p); DBufFree(&ExprBuf); if (r) return r; PushValStack(va); } } /* OK, we've got a literal value; now, we're looking for the end of the expression, or a binary operator. */ r = ParseExprToken(&ExprBuf, s); if (r) return r; if (*DBufValue(&ExprBuf) == 0 || *DBufValue(&ExprBuf) == ',' || *DBufValue(&ExprBuf) == ']' || *DBufValue(&ExprBuf) == ')') { /* We've hit the end of the expression. Pop off and evaluate until OpStackPtr = OpBase and ValStackPtr = ValBase+1 */ while (OpStackPtr > OpBase) { PopOpStack(op); if (DebugFlag & DB_PRTEXPR) r=DebugPerform(&op); else r=(op.func)(); if (r) { DBufFree(&ExprBuf); Eprint("`%s': %s", op.name, ErrMsg[r]); return r; } } if (ValStackPtr != ValBase+1) { DBufFree(&ExprBuf); return E_STACK_ERR; } return OK; } /* Must be a binary operator */ o = FindOperator(DBufValue(&ExprBuf), BinOp, NUM_BIN_OPS); DBufFree(&ExprBuf); if (!o) return E_EXPECTING_BINOP; /* While operators of higher or equal precedence are on the stack, pop them off and evaluate */ while (OpStackPtr > OpBase && OpStack[OpStackPtr-1].prec >= o->prec) { PopOpStack(op2); if (r) return r; if (DebugFlag & DB_PRTEXPR) r=DebugPerform(&op2); else r=(op2.func)(); if (r) { Eprint("`%s': %s", op2.name, ErrMsg[r]); return r; } } PushOpStack(*o); } } /***************************************************************/ /* */ /* MakeValue */ /* Generate a literal value. It's either a string, a number, */ /* a date or the value of a symbol. */ /* */ /***************************************************************/ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p) { int len; int h, m, r; if (*s == '\"') { /* It's a literal string "*/ len = strlen(s)-1; v->type = STR_TYPE; v->v.str = malloc(len); if (! v->v.str) { v->type = ERR_TYPE; return E_NO_MEM; } strncpy(v->v.str, s+1, len-1); *(v->v.str+len-1) = 0; return OK; } else if (*s == '\'') { /* It's a literal date */ s++; if ((r=ParseLiteralDate(&s, &h, &m))) return r; if (*s != '\'') return E_BAD_DATE; if (m == NO_TIME) { v->type = DATE_TYPE; v->v.val = h; } else { v->type = DATETIME_TYPE; v->v.val = (h * MINUTES_PER_DAY) + m; } return OK; } else if (isdigit(*s)) { /* It's a number - use len to hold it.*/ len = 0; while (*s && isdigit(*s)) { len *= 10; len += (*s++ - '0'); } if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */ s++; if (!isdigit(*s)) return E_BAD_TIME; h = len; m = 0; while (isdigit(*s)) { m *= 10; m += *s - '0'; s++; } if (*s || h>23 || m>59) return E_BAD_TIME; v->type = TIME_TYPE; v->v.val = h*60 + m; return OK; } /* Not a time - must be a number */ if (*s) return E_BAD_NUMBER; v->type = INT_TYPE; v->v.val = len; return OK; } else if (*s == '$') { /* A system variable */ if (p) p->nonconst_expr = 1; if (DebugFlag & DB_PRTEXPR) fprintf(ErrFp, "%s => ", s); r = GetSysVar(s+1, v); if (! (DebugFlag & DB_PRTEXPR)) return r; if (r == OK) { PrintValue(v, ErrFp); Putc('\n', ErrFp); } return r; } else { /* Must be a symbol */ if (DebugFlag & DB_PRTEXPR) fprintf(ErrFp, "%s => ", s); } r = GetVarValue(s, v, locals, p); if (! (DebugFlag & DB_PRTEXPR)) return r; if (r == OK) { PrintValue(v, ErrFp); Putc('\n', ErrFp); } return r; } /***************************************************************/ /* */ /* DoCoerce - actually coerce a value to the specified type. */ /* */ /***************************************************************/ int DoCoerce(char type, Value *v) { int h, d, m, y, i, k; char const *s; /* Do nothing if value is already the right type */ if (type == v->type) return OK; switch(type) { case DATETIME_TYPE: switch(v->type) { case INT_TYPE: v->type = DATETIME_TYPE; return OK; case DATE_TYPE: v->type = DATETIME_TYPE; v->v.val *= MINUTES_PER_DAY; return OK; case STR_TYPE: s = v->v.str; if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE; if (*s) return E_CANT_COERCE; v->type = DATETIME_TYPE; free(v->v.str); if (m == NO_TIME) m = 0; v->v.val = i * MINUTES_PER_DAY + m; return OK; default: return E_CANT_COERCE; } case STR_TYPE: switch(v->type) { case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break; case TIME_TYPE: sprintf(CoerceBuf, "%02d%c%02d", v->v.val / 60, TimeSep, v->v.val % 60); break; case DATE_TYPE: FromJulian(v->v.val, &y, &m, &d); sprintf(CoerceBuf, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d); break; case DATETIME_TYPE: i = v->v.val / MINUTES_PER_DAY; FromJulian(i, &y, &m, &d); k = v->v.val % MINUTES_PER_DAY; h = k / 60; i = k % 60; sprintf(CoerceBuf, "%04d%c%02d%c%02d@%02d%c%02d", y, DateSep, m+1, DateSep, d, h, TimeSep, i); break; default: return E_CANT_COERCE; } v->type = STR_TYPE; v->v.str = StrDup(CoerceBuf); if (!v->v.str) { v->type = ERR_TYPE; return E_NO_MEM; } return OK; case INT_TYPE: i = 0; m = 1; switch(v->type) { case STR_TYPE: s = v->v.str; if (*s == '-') { m = -1; s++; } while(*s && isdigit(*s)) { i *= 10; i += (*s++) - '0'; } if (*s) { free (v->v.str); v->type = ERR_TYPE; return E_CANT_COERCE; } free(v->v.str); v->type = INT_TYPE; v->v.val = i * m; return OK; case DATE_TYPE: case TIME_TYPE: case DATETIME_TYPE: v->type = INT_TYPE; return OK; default: return E_CANT_COERCE; } case DATE_TYPE: switch(v->type) { case INT_TYPE: if(v->v.val >= 0) { v->type = DATE_TYPE; return OK; } else return E_2LOW; case STR_TYPE: s = v->v.str; if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE; if (*s) return E_CANT_COERCE; v->type = DATE_TYPE; free(v->v.str); v->v.val = i; return OK; case DATETIME_TYPE: v->type = DATE_TYPE; v->v.val /= MINUTES_PER_DAY; return OK; default: return E_CANT_COERCE; } case TIME_TYPE: switch(v->type) { case INT_TYPE: case DATETIME_TYPE: v->type = TIME_TYPE; v->v.val %= MINUTES_PER_DAY; if (v->v.val < 0) v->v.val += MINUTES_PER_DAY; return OK; case STR_TYPE: h = 0; m = 0; s = v->v.str; if (!isdigit(*s)) return E_CANT_COERCE; while (isdigit(*s)) { h *= 10; h += *s++ - '0'; } if (*s != ':' && *s != '.' && *s != TimeSep) return E_CANT_COERCE; s++; if (!isdigit(*s)) return E_CANT_COERCE; while (isdigit(*s)) { m *= 10; m += *s++ - '0'; } if (*s || h>23 || m>59) return E_CANT_COERCE; v->type = TIME_TYPE; free(v->v.str); v->v.val = h*60+m; return OK; default: return E_CANT_COERCE; } default: return E_CANT_COERCE; } } /***************************************************************/ /* */ /* Add */ /* */ /* Perform addition. */ /* */ /***************************************************************/ static int Add(void) { Value v1, v2, v3; int r; size_t l1, l2; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } /* If both are ints, just add 'em */ if (v2.type == INT_TYPE && v1.type == INT_TYPE) { v2.v.val += v1.v.val; PushValStack(v2); return OK; } /* If it's a date plus an int, add 'em */ if ((v1.type == DATE_TYPE && v2.type == INT_TYPE) || (v1.type == INT_TYPE && v2.type == DATE_TYPE)) { v1.v.val += v2.v.val; if (v1.v.val < 0) return E_DATE_OVER; v1.type = DATE_TYPE; PushValStack(v1); return OK; } /* If it's a datetime plus an int, add 'em */ if ((v1.type == DATETIME_TYPE && v2.type == INT_TYPE) || (v1.type == INT_TYPE && v2.type == DATETIME_TYPE)) { v1.v.val += v2.v.val; if (v1.v.val < 0) return E_DATE_OVER; v1.type = DATETIME_TYPE; PushValStack(v1); return OK; } /* If it's a time plus an int, add 'em mod MINUTES_PER_DAY */ if ((v1.type == TIME_TYPE && v2.type == INT_TYPE) || (v1.type == INT_TYPE && v2.type == TIME_TYPE)) { v1.v.val = (v1.v.val + v2.v.val) % MINUTES_PER_DAY; if (v1.v.val < 0) v1.v.val += MINUTES_PER_DAY; v1.type = TIME_TYPE; PushValStack(v1); return OK; } /* If either is a string, coerce them both to strings and concatenate */ if (v1.type == STR_TYPE || v2.type == STR_TYPE) { if ( (r = DoCoerce(STR_TYPE, &v1)) ) { DestroyValue(v1); DestroyValue(v2); return r; } if ( (r = DoCoerce(STR_TYPE, &v2)) ) { DestroyValue(v1); DestroyValue(v2); return r; } v3.type = STR_TYPE; l1 = strlen(v1.v.str); l2 = strlen(v2.v.str); if (MaxStringLen && (l1 + l2 > MaxStringLen)) { DestroyValue(v1); DestroyValue(v2); return E_STRING_TOO_LONG; } v3.v.str = malloc(l1 + l2 + 1); if (!v3.v.str) { DestroyValue(v1); DestroyValue(v2); return E_NO_MEM; } strcpy(v3.v.str, v1.v.str); strcat(v3.v.str, v2.v.str); DestroyValue(v1); DestroyValue(v2); PushValStack(v3); return OK; } /* Don't handle other types yet */ return E_BAD_TYPE; } /***************************************************************/ /* */ /* Subtract */ /* */ /* Perform subtraction. */ /* */ /***************************************************************/ static int Subtract(void) { Value v1, v2; int r; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } /* If they're both INTs, do subtraction */ if (v1.type == INT_TYPE && v2.type == INT_TYPE) { v1.v.val -= v2.v.val; PushValStack(v1); return OK; } /* If it's a date minus an int, do subtraction, checking for underflow */ if (v1.type == DATE_TYPE && v2.type == INT_TYPE) { v1.v.val -= v2.v.val; if (v1.v.val < 0) return E_DATE_OVER; PushValStack(v1); return OK; } /* If it's a datetime minus an int, do subtraction, checking for underflow */ if (v1.type == DATETIME_TYPE && v2.type == INT_TYPE) { v1.v.val -= v2.v.val; if (v1.v.val < 0) return E_DATE_OVER; PushValStack(v1); return OK; } /* If it's a time minus an int, do subtraction mod MINUTES_PER_DAY */ if (v1.type == TIME_TYPE && v2.type == INT_TYPE) { v1.v.val = (v1.v.val - v2.v.val) % MINUTES_PER_DAY; if (v1.v.val < 0) v1.v.val += MINUTES_PER_DAY; PushValStack(v1); return OK; } /* If it's a time minus a time or a date minus a date, do it */ if ((v1.type == TIME_TYPE && v2.type == TIME_TYPE) || (v1.type == DATETIME_TYPE && v2.type == DATETIME_TYPE) || (v1.type == DATE_TYPE && v2.type == DATE_TYPE)) { v1.v.val -= v2.v.val; v1.type = INT_TYPE; PushValStack(v1); return OK; } /* Must be types illegal for subtraction */ DestroyValue(v1); DestroyValue(v2); return E_BAD_TYPE; } /***************************************************************/ /* */ /* Multiply */ /* */ /* Perform multiplication. */ /* */ /***************************************************************/ static int Multiply(void) { Value v1, v2; int r; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } if (v1.type == INT_TYPE && v2.type == INT_TYPE) { v1.v.val *= v2.v.val; PushValStack(v1); return OK; } DestroyValue(v1); DestroyValue(v2); return E_BAD_TYPE; } /***************************************************************/ /* */ /* Divide */ /* */ /* Perform division. */ /* */ /***************************************************************/ static int Divide(void) { Value v1, v2; int r; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } if (v1.type == INT_TYPE && v2.type == INT_TYPE) { if (v2.v.val == 0) return E_DIV_ZERO; v1.v.val /= v2.v.val; PushValStack(v1); return OK; } DestroyValue(v1); DestroyValue(v2); return E_BAD_TYPE; } /***************************************************************/ /* */ /* Mod */ /* */ /* Perform modulus function. */ /* */ /***************************************************************/ static int Mod(void) { Value v1, v2; int r; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } if (v1.type == INT_TYPE && v2.type == INT_TYPE) { if (v2.v.val == 0) return E_DIV_ZERO; v1.v.val %= v2.v.val; PushValStack(v1); return OK; } DestroyValue(v1); DestroyValue(v2); return E_BAD_TYPE; } /***************************************************************/ /* */ /* GreaterThan, LessThan, EqualTo, NotEqual, LessOrEqual, */ /* GreaterOrEqual */ /* */ /* All the comparison functions. */ /* */ /***************************************************************/ static int GreaterThan(void) {return Compare(GT);} static int LessThan(void) {return Compare(LT);} static int EqualTo(void) {return Compare(EQ);} static int NotEqual(void) {return Compare(NE);} static int LessOrEqual(void) {return Compare(LE);} static int GreaterOrEqual(void) {return Compare(GE);} /***************************************************************/ /* */ /* Compare */ /* Do the actual work of comparison. */ /* */ /***************************************************************/ static int Compare(int how) { Value v1, v2, v3; int r; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } /* Special case for EQ and NE */ v3.type = INT_TYPE; if (v1.type != v2.type) { DestroyValue(v1); DestroyValue(v2); if (how == EQ) { v3.v.val = 0; PushValStack(v3); return OK; } else if (how == NE) { v3.v.val = 1; PushValStack(v3); return OK; } else return E_BAD_TYPE; } if (v1.type == STR_TYPE) { switch(how) { case EQ: v3.v.val = (strcmp(v1.v.str, v2.v.str) == 0); break; case NE: v3.v.val = (strcmp(v1.v.str, v2.v.str) != 0); break; case LT: v3.v.val = (strcmp(v1.v.str, v2.v.str) < 0); break; case GT: v3.v.val = (strcmp(v1.v.str, v2.v.str) > 0); break; case LE: v3.v.val = (strcmp(v1.v.str, v2.v.str) <= 0); break; case GE: v3.v.val = (strcmp(v1.v.str, v2.v.str) >= 0); break; } } else { switch(how) { case EQ: v3.v.val = (v1.v.val == v2.v.val); break; case NE: v3.v.val = (v1.v.val != v2.v.val); break; case LT: v3.v.val = (v1.v.val < v2.v.val); break; case GT: v3.v.val = (v1.v.val > v2.v.val); break; case LE: v3.v.val = (v1.v.val <= v2.v.val); break; case GE: v3.v.val = (v1.v.val >= v2.v.val); break; } } DestroyValue(v1); DestroyValue(v2); PushValStack(v3); return OK; } /***************************************************************/ /* */ /* LogOR */ /* */ /* Do logical OR */ /* */ /***************************************************************/ static int LogOR(void) { Value v1, v2; int r; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } if (v1.type == INT_TYPE && v2.type == INT_TYPE) { v1.v.val = (v1.v.val || v2.v.val) ? 1 : 0; PushValStack(v1); return OK; } DestroyValue(v1); DestroyValue(v2); return E_BAD_TYPE; } /***************************************************************/ /* */ /* LogAND */ /* */ /* Do logical AND */ /* */ /***************************************************************/ static int LogAND(void) { Value v1, v2; int r; PopValStack(v2); if ( (r = FnPopValStack(&v1)) ) { DestroyValue(v2); return r; } if (v1.type == INT_TYPE && v2.type == INT_TYPE) { v1.v.val = (v1.v.val && v2.v.val) ? 1 : 0; PushValStack(v1); return OK; } DestroyValue(v1); DestroyValue(v2); return E_BAD_TYPE; } /***************************************************************/ /* */ /* UnMinus */ /* */ /* Unary Minus */ /* */ /***************************************************************/ static int UnMinus(void) { Value *v = &ValStack[ValStackPtr-1]; if (v->type != INT_TYPE) return E_BAD_TYPE; v->v.val = -v->v.val; return OK; } /***************************************************************/ /* */ /* LogNot */ /* */ /* Logical NOT */ /* */ /***************************************************************/ static int LogNot(void) { Value *v = &ValStack[ValStackPtr-1]; if (v->type != INT_TYPE) return E_BAD_TYPE; if (v->v.val) v->v.val = 0; else v->v.val = 1; return OK; } /***************************************************************/ /* */ /* FindFunc */ /* */ /* Find a function. */ /* */ /***************************************************************/ Operator *FindOperator(char const *name, Operator where[], int num) { int top=num-1, bot=0; int mid, r; while (top >= bot) { mid = (top + bot) / 2; r = StrCmpi(name, where[mid].name); if (!r) return &where[mid]; else if (r > 0) bot = mid+1; else top = mid-1; } return NULL; } /***************************************************************/ /* */ /* FindFunc */ /* */ /* Find a function. */ /* */ /***************************************************************/ BuiltinFunc *FindFunc(char const *name, BuiltinFunc where[], int num) { int top=num-1, bot=0; int mid, r; while (top >= bot) { mid = (top + bot) / 2; r = StrCmpi(name, where[mid].name); if (!r) return &where[mid]; else if (r > 0) bot = mid+1; else top = mid-1; } return NULL; } /***************************************************************/ /* */ /* PrintValue */ /* */ /* Print a value to stdout for debugging purposes. */ /* */ /***************************************************************/ void PrintValue (Value *v, FILE *fp) { int y, m, d; char const *s; if (v->type == STR_TYPE) { s=v->v.str; Putc('"', fp); for (y=0; ytype == INT_TYPE) fprintf(fp, "%d", v->v.val); else if (v->type == TIME_TYPE) fprintf(fp, "%02d%c%02d", v->v.val / 60, TimeSep, v->v.val % 60); else if (v->type == DATE_TYPE) { FromJulian(v->v.val, &y, &m, &d); fprintf(fp, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d); } else if (v->type == DATETIME_TYPE) { FromJulian(v->v.val / MINUTES_PER_DAY, &y, &m, &d); fprintf(fp, "%04d%c%02d%c%02d@%02d%c%02d", y, DateSep, m+1, DateSep, d, (v->v.val % MINUTES_PER_DAY) / 60, TimeSep, (v->v.val % MINUTES_PER_DAY) % 60); } else fprintf(fp, "ERR"); } /***************************************************************/ /* */ /* CopyValue */ /* */ /* Copy a value. */ /* */ /***************************************************************/ int CopyValue(Value *dest, const Value *src) { dest->type = ERR_TYPE; if (src->type == STR_TYPE) { dest->v.str = StrDup(src->v.str); if (!dest->v.str) return E_NO_MEM; } else { dest->v.val = src->v.val; } dest->type = src->type; return OK; } /***************************************************************/ /* */ /* ParseLiteralDate */ /* */ /* Parse a literal date or datetime. Return result in jul */ /* and tim; update s. */ /* */ /***************************************************************/ int ParseLiteralDate(char const **s, int *jul, int *tim) { int y, m, d; int hour, min; y=0; m=0; d=0; hour=0; min=0; *tim = NO_TIME; if (!isdigit(**s)) return E_BAD_DATE; while (isdigit(**s)) { y *= 10; y += *(*s)++ - '0'; } if (**s != '/' && **s != '-' && **s != DateSep) return E_BAD_DATE; (*s)++; if (!isdigit(**s)) return E_BAD_DATE; while (isdigit(**s)) { m *= 10; m += *(*s)++ - '0'; } m--; if (**s != '/' && **s != '-' && **s != DateSep) return E_BAD_DATE; (*s)++; if (!isdigit(**s)) return E_BAD_DATE; while (isdigit(**s)) { d *= 10; d += *(*s)++ - '0'; } if (!DateOK(y, m, d)) return E_BAD_DATE; *jul = Julian(y, m, d); /* Do we have a time part as well? */ if (**s == ' ' || **s == '@') { (*s)++; while(isdigit(**s)) { hour *= 10; hour += *(*s)++ - '0'; } if (**s != ':' && **s != '.' && **s != TimeSep) return E_BAD_TIME; (*s)++; while(isdigit(**s)) { min *= 10; min += *(*s)++ - '0'; } if (hour > 23 || min > 59) return E_BAD_TIME; *tim = hour * 60 + min; } return OK; } /***************************************************************/ /* */ /* FnPopValStack */ /* */ /* Pop a value from the value stack - implemented as a */ /* function for situations where we don't want an immediate */ /* return upon failure. */ /* */ /***************************************************************/ int FnPopValStack(Value *val) { if (ValStackPtr <= 0) return E_VA_STK_UNDER; else { *val = ValStack[--ValStackPtr]; return OK; } } remind-03.01.15/src/expr.h0000644000076400007640000000341312514120721013253 0ustar dfsdfs/***************************************************************/ /* */ /* EXPR.H */ /* */ /* Contains a few definitions used by expression evaluator. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* Define the types of values */ #define ERR_TYPE 0 #define INT_TYPE 1 #define TIME_TYPE 2 #define DATE_TYPE 3 #define STR_TYPE 4 #define DATETIME_TYPE 5 #define SPECIAL_TYPE 6 /* Only for system variables */ /* Define stuff for parsing expressions */ #define BEG_OF_EXPR '[' #define END_OF_EXPR ']' #define COMMA ',' #define UN_OP 0 /* Unary operator */ #define BIN_OP 1 /* Binary Operator */ #define FUNC 2 /* Function */ /* Make the pushing and popping of values and operators in-line code for speed. BEWARE: These macros invoke return if an error happens ! */ #define PushOpStack(op) \ if (OpStackPtr >= OP_STACK_SIZE) \ return E_OP_STK_OVER; \ else \ OpStack[OpStackPtr++] = (op) #define PopOpStack(op) \ if (OpStackPtr <= 0) \ return E_OP_STK_UNDER; \ else \ (op) = OpStack[--OpStackPtr] #define PushValStack(val) \ if (ValStackPtr >= VAL_STACK_SIZE) \ return E_VA_STK_OVER; \ else \ ValStack[ValStackPtr++] = (val) #define PopValStack(val) \ if (ValStackPtr <= 0) \ return E_VA_STK_UNDER; \ else \ (val) = ValStack[--ValStackPtr] remind-03.01.15/src/files.c0000644000076400007640000005445712514120716013414 0ustar dfsdfs/***************************************************************/ /* */ /* FILES.C */ /* */ /* Controls the opening and closing of files, etc. Also */ /* handles caching of lines and reading of lines from */ /* files. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #include #ifdef TM_IN_SYS_TIME #include #else #include #endif #include #include #include #ifdef HAVE_GLOB_H #include #endif #include "types.h" #include "protos.h" #include "globals.h" #include "err.h" /* Convenient macro for closing files */ #define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL)) /* Define the structures needed by the file caching system */ typedef struct cache { struct cache *next; char const *text; int LineNo; } CachedLine; typedef struct cheader { struct cheader *next; char const *filename; CachedLine *cache; int ownedByMe; } CachedFile; /* A linked list of filenames if we INCLUDE /some/directory/ */ typedef struct fname_chain { struct fname_chain *next; char const *filename; } FilenameChain; /* Cache filename chains for directories */ typedef struct directory_fname_chain { struct directory_fname_chain *next; FilenameChain *chain; char const *dirname; } DirectoryFilenameChain; /* Define the structures needed by the INCLUDE file system */ typedef struct { char const *filename; FilenameChain *chain; int LineNo; unsigned int IfFlags; int NumIfs; long offset; CachedLine *CLine; int ownedByMe; } IncludeStruct; static CachedFile *CachedFiles = (CachedFile *) NULL; static CachedLine *CLine = (CachedLine *) NULL; static DirectoryFilenameChain *CachedDirectoryChains = NULL; static FILE *fp; static IncludeStruct IStack[INCLUDE_NEST]; static int IStackPtr = 0; static int ReadLineFromFile (void); static int CacheFile (char const *fname); static void DestroyCache (CachedFile *cf); static int CheckSafety (void); static int PopFile (void); static void OpenPurgeFile(char const *fname, char const *mode) { DynamicBuffer fname_buf; if (PurgeFP != NULL && PurgeFP != stdout) { fclose(PurgeFP); } PurgeFP = NULL; /* Do not open a purge file if we're below purge include depth */ if (IStackPtr-2 >= PurgeIncludeDepth) { PurgeFP = NULL; return; } DBufInit(&fname_buf); if (DBufPuts(&fname_buf, fname) != OK) return; if (DBufPuts(&fname_buf, ".purged") != OK) return; PurgeFP = fopen(DBufValue(&fname_buf), mode); if (!PurgeFP) { fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno)); } DBufFree(&fname_buf); } static void FreeChainItem(FilenameChain *chain) { if (chain->filename) free((void *) chain->filename); free(chain); } static void FreeChain(FilenameChain *chain) { FilenameChain *next; while(chain) { next = chain->next; FreeChainItem(chain); chain = next; } } /***************************************************************/ /* */ /* ReadLine */ /* */ /* Read a line from the file or cache. */ /* */ /***************************************************************/ int ReadLine(void) { int r; /* If we're at the end of a file, pop */ while (!CLine && !fp) { r = PopFile(); if (r) return r; } /* If it's cached, read line from the cache */ if (CLine) { CurLine = CLine->text; LineNo = CLine->LineNo; CLine = CLine->next; FreshLine = 1; if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp); return OK; } /* Not cached. Read from the file. */ return ReadLineFromFile(); } /***************************************************************/ /* */ /* ReadLineFromFile */ /* */ /* Read a line from the file pointed to by fp. */ /* */ /***************************************************************/ static int ReadLineFromFile(void) { int l; char copy_buffer[4096]; size_t n; DynamicBuffer buf; DBufInit(&buf); DBufFree(&LineBuffer); while(fp) { if (DBufGets(&buf, fp) != OK) { DBufFree(&LineBuffer); return E_NO_MEM; } LineNo++; if (ferror(fp)) { DBufFree(&buf); DBufFree(&LineBuffer); return E_IO_ERR; } if (feof(fp)) { FCLOSE(fp); if ((DBufLen(&buf) == 0) && (DBufLen(&LineBuffer) == 0) && PurgeMode) { if (PurgeFP != NULL && PurgeFP != stdout) fclose(PurgeFP); PurgeFP = NULL; } } l = DBufLen(&buf); if (l && (DBufValue(&buf)[l-1] == '\\')) { if (PurgeMode) { if (DBufPuts(&LineBuffer, DBufValue(&buf)) != OK) { DBufFree(&buf); DBufFree(&LineBuffer); return E_NO_MEM; } if (DBufPutc(&LineBuffer, '\n') != OK) { DBufFree(&buf); DBufFree(&LineBuffer); return E_NO_MEM; } } else { DBufValue(&buf)[l-1] = '\n'; if (DBufPuts(&LineBuffer, DBufValue(&buf)) != OK) { DBufFree(&buf); DBufFree(&LineBuffer); return E_NO_MEM; } } continue; } if (DBufPuts(&LineBuffer, DBufValue(&buf)) != OK) { DBufFree(&buf); DBufFree(&LineBuffer); return E_NO_MEM; } DBufFree(&buf); /* If the line is: __EOF__ treat it as end-of-file */ CurLine = DBufValue(&LineBuffer); if (!strcmp(CurLine, "__EOF__")) { if (PurgeMode && PurgeFP) { PurgeEchoLine("%s\n", "__EOF__"); while ((n = fread(copy_buffer, 1, sizeof(copy_buffer), fp)) != 0) { fwrite(copy_buffer, 1, n, PurgeFP); } if (PurgeFP != stdout) fclose(PurgeFP); PurgeFP = NULL; } FCLOSE(fp); DBufFree(&LineBuffer); CurLine = DBufValue(&LineBuffer); } FreshLine = 1; if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp); return OK; } CurLine = DBufValue(&LineBuffer); return OK; } /***************************************************************/ /* */ /* OpenFile */ /* */ /* Open a file for reading. If it's in the cache, set */ /* CLine. Otherwise, open it on disk and set fp. If */ /* ShouldCache is 1, cache the file */ /* */ /***************************************************************/ int OpenFile(char const *fname) { CachedFile *h = CachedFiles; int r; if (PurgeMode) { if (PurgeFP != NULL && PurgeFP != stdout) { fclose(PurgeFP); } PurgeFP = NULL; } /* Assume we own the file for now */ RunDisabled &= ~RUN_NOTOWNER; /* If it's in the cache, get it from there. */ while (h) { if (!strcmp(fname, h->filename)) { if (DebugFlag & DB_TRACE_FILES) { fprintf(ErrFp, "Reading `%s': Found in cache\n", fname); } CLine = h->cache; STRSET(FileName, fname); LineNo = 0; if (!h->ownedByMe) { RunDisabled |= RUN_NOTOWNER; } if (FileName) return OK; else return E_NO_MEM; } h = h->next; } /* If it's a dash, then it's stdin */ if (!strcmp(fname, "-")) { fp = stdin; if (PurgeMode) { PurgeFP = stdout; } if (DebugFlag & DB_TRACE_FILES) { fprintf(ErrFp, "Reading `-': Reading stdin\n"); } } else { fp = fopen(fname, "r"); if (DebugFlag & DB_TRACE_FILES) { fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname); } if (PurgeMode) { OpenPurgeFile(fname, "w"); } } if (!fp || !CheckSafety()) return E_CANT_OPEN; CLine = NULL; if (ShouldCache) { LineNo = 0; r = CacheFile(fname); if (r == OK) { fp = NULL; CLine = CachedFiles->cache; } else { if (strcmp(fname, "-")) { fp = fopen(fname, "r"); if (!fp || !CheckSafety()) return E_CANT_OPEN; if (PurgeMode) OpenPurgeFile(fname, "w"); } else { fp = stdin; if (PurgeMode) PurgeFP = stdout; } } } STRSET(FileName, fname); LineNo = 0; if (FileName) return OK; else return E_NO_MEM; } /***************************************************************/ /* */ /* CacheFile */ /* */ /* Cache a file in memory. If we fail, set ShouldCache to 0 */ /* Returns an indication of success or failure. */ /* */ /***************************************************************/ static int CacheFile(char const *fname) { int r; CachedFile *cf; CachedLine *cl; char const *s; if (DebugFlag & DB_TRACE_FILES) { fprintf(ErrFp, "Caching file `%s' in memory\n", fname); } cl = NULL; /* Create a file header */ cf = NEW(CachedFile); cf->cache = NULL; if (!cf) { ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } cf->filename = StrDup(fname); if (!cf->filename) { ShouldCache = 0; FCLOSE(fp); free(cf); return E_NO_MEM; } if (RunDisabled & RUN_NOTOWNER) { cf->ownedByMe = 0; } else { cf->ownedByMe = 1; } /* Read the file */ while(fp) { r = ReadLineFromFile(); if (r) { DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return r; } /* Skip blank chars */ s = DBufValue(&LineBuffer); while (isempty(*s)) s++; if (*s && *s!=';' && *s!='#') { /* Add the line to the cache */ if (!cl) { cf->cache = NEW(CachedLine); if (!cf->cache) { DBufFree(&LineBuffer); DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } cl = cf->cache; } else { cl->next = NEW(CachedLine); if (!cl->next) { DBufFree(&LineBuffer); DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } cl = cl->next; } cl->next = NULL; cl->LineNo = LineNo; cl->text = StrDup(s); DBufFree(&LineBuffer); if (!cl->text) { DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } } } /* Put the cached file at the head of the queue */ cf->next = CachedFiles; CachedFiles = cf; return OK; } /***************************************************************/ /* */ /* NextChainedFile - move to the next chained file in a glob */ /* list. */ /* */ /***************************************************************/ static int NextChainedFile(IncludeStruct *i) { while(i->chain) { FilenameChain *cur = i->chain; i->chain = i->chain->next; if (OpenFile(cur->filename) == OK) { return OK; } else { Eprint("%s: %s", ErrMsg[E_CANT_OPEN], cur->filename); } } return E_EOF; } /***************************************************************/ /* */ /* PopFile - we've reached the end. Pop up to the previous */ /* file, or return E_EOF */ /* */ /***************************************************************/ static int PopFile(void) { IncludeStruct *i; /* Assume we own the file for now */ RunDisabled &= ~RUN_NOTOWNER; if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]); if (!IStackPtr) return E_EOF; i = &IStack[IStackPtr-1]; if (i->chain) { int oldRunDisabled = RunDisabled; if (NextChainedFile(i) == OK) { return OK; } RunDisabled = oldRunDisabled; } if (IStackPtr <= 1) { return E_EOF; } IStackPtr--; LineNo = i->LineNo; IfFlags = i->IfFlags; NumIfs = i->NumIfs; CLine = i->CLine; fp = NULL; STRSET(FileName, i->filename); if (!i->ownedByMe) { RunDisabled |= RUN_NOTOWNER; } if (!CLine && (i->offset != -1L)) { /* We must open the file, then seek to specified position */ if (strcmp(i->filename, "-")) { fp = fopen(i->filename, "r"); if (!fp || !CheckSafety()) return E_CANT_OPEN; if (PurgeMode) OpenPurgeFile(i->filename, "a"); } else { fp = stdin; if (PurgeMode) PurgeFP = stdout; } if (fp != stdin) (void) fseek(fp, i->offset, 0); /* Trust that it works... */ } free((char *) i->filename); return OK; } /***************************************************************/ /* */ /* DoInclude */ /* */ /* The INCLUDE command. */ /* */ /***************************************************************/ int DoInclude(ParsePtr p) { DynamicBuffer buf; int r, e; DBufInit(&buf); if ( (r=ParseToken(p, &buf)) ) return r; e = VerifyEoln(p); if (e) Eprint("%s", ErrMsg[e]); if ( (r=IncludeFile(DBufValue(&buf))) ) { DBufFree(&buf); return r; } DBufFree(&buf); NumIfs = 0; IfFlags = 0; return OK; } #ifdef HAVE_GLOB static int SetupGlobChain(char const *dirname, IncludeStruct *i) { DynamicBuffer pattern; char *dir; size_t l; int r; glob_t glob_buf; DirectoryFilenameChain *dc = CachedDirectoryChains; i->chain = NULL; if (!*dirname) return E_CANT_OPEN; dir = StrDup(dirname); if (!dir) return E_NO_MEM; /* Strip trailing slashes off directory */ l = strlen(dir); while(l) { if (*(dir+l-1) == '/') { l--; *(dir+l) = 0; } else { break; } } /* Repair root directory :-) */ if (!l) { *dir = '/'; } /* Check the cache */ while(dc) { if (!strcmp(dc->dirname, dir)) { if (DebugFlag & DB_TRACE_FILES) { fprintf(ErrFp, "Found cached directory listing for `%s'\n", dir); } free(dir); i->chain = dc->chain; return OK; } dc = dc->next; } if (DebugFlag & DB_TRACE_FILES) { fprintf(ErrFp, "Scanning directory `%s' for *.rem files\n", dir); } if (ShouldCache) { dc = malloc(sizeof(DirectoryFilenameChain)); if (dc) { dc->dirname = StrDup(dir); if (!dc->dirname) { free(dc); dc = NULL; } } if (dc) { if (DebugFlag & DB_TRACE_FILES) { fprintf(ErrFp, "Caching directory `%s' listing\n", dir); } dc->chain = NULL; dc->next = CachedDirectoryChains; CachedDirectoryChains = dc; } } DBufInit(&pattern); DBufPuts(&pattern, dir); DBufPuts(&pattern, "/*.rem"); free(dir); r = glob(DBufValue(&pattern), 0, NULL, &glob_buf); DBufFree(&pattern); if (r == GLOB_NOMATCH) { globfree(&glob_buf); return OK; } if (r != 0) { globfree(&glob_buf); return -1; } /* Add the files to the chain backwards to preserve sort order */ for (r=glob_buf.gl_pathc-1; r>=0; r--) { FilenameChain *ch = malloc(sizeof(FilenameChain)); if (!ch) { globfree(&glob_buf); FreeChain(i->chain); i->chain = NULL; return E_NO_MEM; } /* TODO: stat the file and only add if it's a plain file and readable by us */ ch->filename = StrDup(glob_buf.gl_pathv[r]); if (!ch->filename) { globfree(&glob_buf); FreeChain(i->chain); i->chain = NULL; free(ch); return E_NO_MEM; } ch->next = i->chain; i->chain = ch; } if (dc) { dc->chain = i->chain; } globfree(&glob_buf); return OK; } #endif /***************************************************************/ /* */ /* IncludeFile */ /* */ /* Process the INCLUDE command - actually do the file */ /* inclusion. */ /* */ /***************************************************************/ int IncludeFile(char const *fname) { IncludeStruct *i; int oldRunDisabled; struct stat statbuf; FreshLine = 1; if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE; i = &IStack[IStackPtr]; if (FileName) { i->filename = StrDup(FileName); if (!i->filename) return E_NO_MEM; } else { i->filename = NULL; } i->LineNo = LineNo; i->NumIfs = NumIfs; i->IfFlags = IfFlags; i->CLine = CLine; i->offset = -1L; i->chain = NULL; if (RunDisabled & RUN_NOTOWNER) { i->ownedByMe = 0; } else { i->ownedByMe = 1; } if (fp) { i->offset = ftell(fp); FCLOSE(fp); } IStackPtr++; #ifdef HAVE_GLOB /* If it's a directory, set up the glob chain here. */ if (stat(fname, &statbuf) == 0) { FilenameChain *fc; if (S_ISDIR(statbuf.st_mode)) { if (SetupGlobChain(fname, i) == OK) { /* Glob succeeded */ if (!i->chain) { /* Oops... no matching files */ if (!Hush) { Eprint("%s: %s", fname, ErrMsg[E_NO_MATCHING_REMS]); } PopFile(); return E_NO_MATCHING_REMS; } while(i->chain) { fc = i->chain; i->chain = i->chain->next; /* Munch first file */ oldRunDisabled = RunDisabled; if (!OpenFile(fc->filename)) { return OK; } Eprint("%s: %s", ErrMsg[E_CANT_OPEN], fc->filename); RunDisabled = oldRunDisabled; } /* Couldn't open anything... bail */ return PopFile(); } else { if (!Hush) { Eprint("%s: %s", fname, ErrMsg[E_NO_MATCHING_REMS]); } } return E_NO_MATCHING_REMS; } } #endif oldRunDisabled = RunDisabled; /* Try to open the new file */ if (!OpenFile(fname)) { return OK; } RunDisabled = oldRunDisabled; Eprint("%s: %s", ErrMsg[E_CANT_OPEN], fname); /* Ugh! We failed! */ PopFile(); return E_CANT_OPEN; } /***************************************************************/ /* */ /* GetAccessDate - get the access date of a file. */ /* */ /***************************************************************/ int GetAccessDate(char const *file) { struct stat statbuf; struct tm *t1; if (stat(file, &statbuf)) return -1; t1 = localtime(&(statbuf.st_atime)); if (t1->tm_year + 1900 < BASE) return 0; else return Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday); } /***************************************************************/ /* */ /* DestroyCache */ /* */ /* Free all the memory used by a cached file. */ /* */ /***************************************************************/ static void DestroyCache(CachedFile *cf) { CachedLine *cl, *cnext; CachedFile *temp; if (cf->filename) free((char *) cf->filename); cl = cf->cache; while (cl) { if (cl->text) free ((char *) cl->text); cnext = cl->next; free(cl); cl = cnext; } if (CachedFiles == cf) CachedFiles = cf->next; else { temp = CachedFiles; while(temp) { if (temp->next == cf) { temp->next = cf->next; break; } temp = temp->next; } } free(cf); } /***************************************************************/ /* */ /* TopLevel */ /* */ /* Returns 1 if current file is top level, 0 otherwise. */ /* */ /***************************************************************/ int TopLevel(void) { return IStackPtr <= 1; } /***************************************************************/ /* */ /* CheckSafety */ /* */ /* Returns 1 if current file is safe to read; 0 otherwise. */ /* Currently only meaningful for UNIX. If we are running as */ /* root, we refuse to open files not owned by root. */ /* We also reject world-writable files, no matter */ /* who we're running as. */ /* As a side effect, if we don't own the file, we disable RUN */ /***************************************************************/ static int CheckSafety(void) { struct stat statbuf; if (fp == stdin) { return 1; } if (fstat(fileno(fp), &statbuf)) { fclose(fp); fp = NULL; return 0; } /* Under UNIX, take extra precautions if running as root */ if (!geteuid()) { /* Reject files not owned by root or group/world writable */ if (statbuf.st_uid != 0) { fprintf(ErrFp, "SECURITY: Won't read non-root-owned file when running as root!\n"); fclose(fp); fp = NULL; return 0; } } /* Sigh... /dev/null is usually world-writable, so ignore devices, FIFOs, sockets, etc. */ if (!S_ISREG(statbuf.st_mode)) { return 1; } if ((statbuf.st_mode & S_IWOTH)) { fprintf(ErrFp, "SECURITY: Won't read world-writable file!\n"); fclose(fp); fp = NULL; return 0; } /* If file is not owned by me, disable RUN command */ if (statbuf.st_uid != geteuid()) { RunDisabled |= RUN_NOTOWNER; } return 1; } remind-03.01.15/src/funcs.c0000644000076400007640000023337012514120712013415 0ustar dfsdfs/***************************************************************/ /* */ /* FUNCS.C */ /* */ /* This file contains the built-in functions used in */ /* expressions. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "version.h" #include "config.h" #include #include #include #include #include #include #ifdef HAVE_SYS_FILE_H #include #endif #include #include #ifdef TM_IN_SYS_TIME #include #else #include #endif #ifndef R_OK #define R_OK 4 #define W_OK 2 #define X_OK 1 #endif #include "types.h" #include "globals.h" #include "protos.h" #include "err.h" #include "expr.h" /* Defines that used to be static variables */ #define Nargs (info->nargs) #define RetVal (info->retval) /* Function prototypes */ static int FCurrent (func_info *); static int FNonomitted (func_info *); static int FTimepart(func_info *); static int FDatepart(func_info *); static int FRealCurrent(func_info *); static int FAbs (func_info *); static int FAccess (func_info *); static int FArgs (func_info *); static int FAsc (func_info *); static int FBaseyr (func_info *); static int FChar (func_info *); static int FChoose (func_info *); static int FCoerce (func_info *); static int FDate (func_info *); static int FDateTime (func_info *); static int FDay (func_info *); static int FDaysinmon (func_info *); static int FDefined (func_info *); static int FDosubst (func_info *); static int FEasterdate (func_info *); static int FEvalTrig (func_info *); static int FFiledate (func_info *); static int FFiledatetime (func_info *); static int FFiledir (func_info *); static int FFilename (func_info *); static int FGetenv (func_info *); static int FHebdate (func_info *); static int FHebday (func_info *); static int FHebmon (func_info *); static int FHebyear (func_info *); static int FHour (func_info *); static int FIif (func_info *); static int FIndex (func_info *); static int FIsdst (func_info *); static int FIsomitted (func_info *); static int FSlide (func_info *); static int FLanguage (func_info *); static int FMax (func_info *); static int FMin (func_info *); static int FMinute (func_info *); static int FMinsfromutc (func_info *); static int FMoondate (func_info *); static int FMoondatetime (func_info *); static int FMoonphase (func_info *); static int FMoontime (func_info *); static int FMon (func_info *); static int FMonnum (func_info *); static int FOrd (func_info *); static int FOstype (func_info *); static int FPlural (func_info *); static int FSgn (func_info *); static int FPsmoon (func_info *); static int FPsshade (func_info *); static int FShell (func_info *); static int FStrlen (func_info *); static int FSubstr (func_info *); static int FDawn (func_info *); static int FDusk (func_info *); static int FSunset (func_info *); static int FSunrise (func_info *); static int FTime (func_info *); static int FTrigdate (func_info *); static int FTrigdatetime (func_info *); static int FTrigtime (func_info *); static int FTrigvalid (func_info *); static int FTypeof (func_info *); static int FUpper (func_info *); static int FValue (func_info *); static int FVersion (func_info *); static int FWkday (func_info *); static int FWkdaynum (func_info *); static int FYear (func_info *); static int FIsleap (func_info *); static int FLower (func_info *); static int FNow (func_info *); static int FRealnow (func_info *); static int FRealtoday (func_info *); static int FToday (func_info *); static int FTrigger (func_info *); static int FTzconvert (func_info *); static int FWeekno (func_info *); static int CheckArgs (BuiltinFunc *f, int nargs); static int CleanUpAfterFunc (func_info *); static int SunStuff (int rise, double cosz, int jul); /* "Overload" the struct Operator definition */ #define NO_MAX 127 /* Caches for extracting months, days, years from dates - may improve performance slightly. */ static int CacheJul = -1; static int CacheYear, CacheMon, CacheDay; static int CacheHebJul = -1; static int CacheHebYear, CacheHebMon, CacheHebDay; /* We need access to the value stack */ extern Value ValStack[]; extern int ValStackPtr; /* Macro for accessing arguments from the value stack - args are numbered from 0 to (Nargs - 1) */ #define ARG(x) (ValStack[ValStackPtr - Nargs + (x)]) #define ARGV(x) ARG(x).v.val #define ARGSTR(x) ARG(x).v.str #define ASSERT_TYPE(x, t) if (ARG(x).type != t) return E_BAD_TYPE /* Macro for getting date part of a date or datetime value */ #define DATEPART(x) ((x).type == DATE_TYPE ? (x).v.val : ((x).v.val / MINUTES_PER_DAY)) /* Macro for getting time part of a time or datetime value */ #define TIMEPART(x) ((x).type == TIME_TYPE ? (x).v.val : ((x).v.val % MINUTES_PER_DAY)) #define HASDATE(x) ((x).type == DATE_TYPE || (x).type == DATETIME_TYPE) #define HASTIME(x) ((x).type == TIME_TYPE || (x).type == DATETIME_TYPE) /* Macro for copying a value while destroying original copy */ #define DCOPYVAL(x, y) ( (x) = (y), (y).type = ERR_TYPE ) /* Get at RetVal.v.val easily */ #define RETVAL info->retval.v.val /* Convenience macros */ #define UPPER(c) (islower(c) ? toupper(c) : c) #define LOWER(c) (isupper(c) ? tolower(c) : c) /* The array holding the built-in functions. */ BuiltinFunc Func[] = { /* Name minargs maxargs is_constant func */ { "abs", 1, 1, 1, FAbs }, { "access", 2, 2, 0, FAccess }, { "args", 1, 1, 0, FArgs }, { "asc", 1, 1, 1, FAsc }, { "baseyr", 0, 0, 1, FBaseyr }, { "char", 1, NO_MAX, 1, FChar }, { "choose", 2, NO_MAX, 1, FChoose }, { "coerce", 2, 2, 1, FCoerce }, { "current", 0, 0, 0, FCurrent }, { "date", 3, 3, 1, FDate }, { "datepart", 1, 1, 1, FDatepart }, { "datetime", 2, 5, 1, FDateTime }, { "dawn", 0, 1, 0, FDawn}, { "day", 1, 1, 1, FDay }, { "daysinmon", 2, 2, 1, FDaysinmon }, { "defined", 1, 1, 0, FDefined }, { "dosubst", 1, 3, 0, FDosubst }, { "dusk", 0, 1, 0, FDusk }, { "easterdate", 1, 1, 0, FEasterdate }, { "evaltrig", 1, 2, 0, FEvalTrig }, { "filedate", 1, 1, 0, FFiledate }, { "filedatetime", 1, 1, 0, FFiledatetime }, { "filedir", 0, 0, 0, FFiledir }, { "filename", 0, 0, 0, FFilename }, { "getenv", 1, 1, 0, FGetenv }, { "hebdate", 2, 5, 0, FHebdate }, { "hebday", 1, 1, 0, FHebday }, { "hebmon", 1, 1, 0, FHebmon }, { "hebyear", 1, 1, 0, FHebyear }, { "hour", 1, 1, 1, FHour }, { "iif", 1, NO_MAX, 1, FIif }, { "index", 2, 3, 1, FIndex }, { "isdst", 0, 2, 0, FIsdst }, { "isleap", 1, 1, 1, FIsleap }, { "isomitted", 1, 1, 0, FIsomitted }, { "language", 0, 0, 1, FLanguage }, { "lower", 1, 1, 1, FLower }, { "max", 1, NO_MAX, 1, FMax }, { "min", 1, NO_MAX, 1, FMin }, { "minsfromutc", 0, 2, 0, FMinsfromutc }, { "minute", 1, 1, 1, FMinute }, { "mon", 1, 1, 1, FMon }, { "monnum", 1, 1, 1, FMonnum }, { "moondate", 1, 3, 0, FMoondate }, { "moondatetime", 1, 3, 0, FMoondatetime }, { "moonphase", 0, 2, 0, FMoonphase }, { "moontime", 1, 3, 0, FMoontime }, { "nonomitted", 2, NO_MAX, 0, FNonomitted }, { "now", 0, 0, 0, FNow }, { "ord", 1, 1, 1, FOrd }, { "ostype", 0, 0, 1, FOstype }, { "plural", 1, 3, 1, FPlural }, { "psmoon", 1, 4, 1, FPsmoon}, { "psshade", 1, 3, 1, FPsshade}, { "realcurrent", 0, 0, 0, FRealCurrent}, { "realnow", 0, 0, 0, FRealnow}, { "realtoday", 0, 0, 0, FRealtoday }, { "sgn", 1, 1, 1, FSgn }, { "shell", 1, 2, 0, FShell }, { "slide", 2, NO_MAX, 0, FSlide }, { "strlen", 1, 1, 1, FStrlen }, { "substr", 2, 3, 1, FSubstr }, { "sunrise", 0, 1, 0, FSunrise}, { "sunset", 0, 1, 0, FSunset }, { "time", 2, 2, 1, FTime }, { "timepart", 1, 1, 1, FTimepart }, { "today", 0, 0, 0, FToday }, { "trigdate", 0, 0, 0, FTrigdate }, { "trigdatetime", 0, 0, 0, FTrigdatetime }, { "trigger", 1, 3, 0, FTrigger }, { "trigtime", 0, 0, 0, FTrigtime }, { "trigvalid", 0, 0, 0, FTrigvalid }, { "typeof", 1, 1, 1, FTypeof }, { "tzconvert", 2, 3, 0, FTzconvert }, { "upper", 1, 1, 1, FUpper }, { "value", 1, 2, 0, FValue }, { "version", 0, 0, 1, FVersion }, { "weekno", 0, 3, 1, FWeekno }, { "wkday", 1, 1, 1, FWkday }, { "wkdaynum", 1, 1, 1, FWkdaynum }, { "year", 1, 1, 1, FYear } }; /* Need a variable here - Func[] array not really visible to outside. */ int NumFuncs = sizeof(Func) / sizeof(Operator) ; /***************************************************************/ /* */ /* CallFunc */ /* */ /* Call a function given a pointer to it, and the number */ /* of arguments supplied. */ /* */ /***************************************************************/ int CallFunc(BuiltinFunc *f, int nargs) { register int r = CheckArgs(f, nargs); int i; func_info info_obj; func_info *info = &info_obj; Nargs = nargs; RetVal.type = ERR_TYPE; if (DebugFlag & DB_PRTEXPR) { fprintf(ErrFp, "%s(", f->name); for (i=0; i "); if (r) { fprintf(ErrFp, "%s\n", ErrMsg[r]); return r; } } if (r) { Eprint("%s(): %s", f->name, ErrMsg[r]); return r; } r = (*(f->func))(info); if (r) { DestroyValue(RetVal); if (DebugFlag & DB_PRTEXPR) fprintf(ErrFp, "%s\n", ErrMsg[r]); else Eprint("%s(): %s", f->name, ErrMsg[r]); return r; } if (DebugFlag & DB_PRTEXPR) { PrintValue(&RetVal, ErrFp); fprintf(ErrFp, "\n"); } r = CleanUpAfterFunc(info); return r; } /***************************************************************/ /* */ /* CheckArgs */ /* */ /* Check that the right number of args have been supplied */ /* for a function. */ /* */ /***************************************************************/ static int CheckArgs(BuiltinFunc *f, int nargs) { if (nargs < f->minargs) return E_2FEW_ARGS; if (nargs > f->maxargs && f->maxargs != NO_MAX) return E_2MANY_ARGS; return OK; } /***************************************************************/ /* */ /* CleanUpAfterFunc */ /* */ /* Clean up the stack after a function call - remove */ /* args and push the new value. */ /* */ /***************************************************************/ static int CleanUpAfterFunc(func_info *info) { Value v; int i; for (i=0; itype != STR_TYPE) return E_BAD_TYPE; RetVal.type = INT_TYPE; RETVAL = strlen(v->v.str); return OK; } /***************************************************************/ /* */ /* FBaseyr - system base year */ /* */ /***************************************************************/ static int FBaseyr(func_info *info) { RetVal.type = INT_TYPE; RETVAL = BASE; return OK; } /***************************************************************/ /* */ /* FDate - make a date from year, month, day. */ /* */ /***************************************************************/ static int FDate(func_info *info) { int y, m, d; int ytemp, mtemp, dtemp; /* Any arg can be a date (in which case we use the corresponding component) or an integer */ if (HASDATE(ARG(0))) { FromJulian(DATEPART(ARG(0)), &ytemp, &mtemp, &dtemp); y = ytemp; } else { ASSERT_TYPE(0, INT_TYPE); y = ARGV(0); } if (HASDATE(ARG(1))) { FromJulian(DATEPART(ARG(1)), &ytemp, &mtemp, &dtemp); m = mtemp; } else { ASSERT_TYPE(1, INT_TYPE); m = ARGV(1) - 1; } if (HASDATE(ARG(2))) { FromJulian(DATEPART(ARG(2)), &ytemp, &mtemp, &dtemp); d = dtemp; } else { ASSERT_TYPE(2, INT_TYPE); d = ARGV(2); } if (!DateOK(y, m, d)) { return E_BAD_DATE; } RetVal.type = DATE_TYPE; RETVAL = Julian(y, m, d); return OK; } /***************************************************************/ /* */ /* FDateTime - make a datetime from one of these combos: */ /* DATE, TIME */ /* DATE, HOUR, MINUTE */ /* YEAR, MONTH, DAY, TIME */ /* YEAR, MONTH, DAY, HOUR, MINUTE */ /* */ /***************************************************************/ static int FDateTime(func_info *info) { int y, m, d; RetVal.type = DATETIME_TYPE; switch(Nargs) { case 2: if (ARG(0).type != DATE_TYPE || ARG(1).type != TIME_TYPE) return E_BAD_TYPE; RETVAL = (MINUTES_PER_DAY * ARGV(0)) + ARGV(1); return OK; case 3: if (ARG(0).type != DATE_TYPE || ARG(1).type != INT_TYPE || ARG(2).type != INT_TYPE) return E_BAD_TYPE; if (ARGV(1) < 0 || ARGV(2) < 0) return E_2LOW; if (ARGV(1) > 23 || ARGV(2) > 59) return E_2HIGH; RETVAL = (MINUTES_PER_DAY * ARGV(0)) + 60 * ARGV(1) + ARGV(2); return OK; case 4: if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE || ARG(2).type != INT_TYPE || ARG(3).type != TIME_TYPE) return E_BAD_TYPE; y = ARGV(0); m = ARGV(1) - 1; d = ARGV(2); if (!DateOK(y, m, d)) return E_BAD_DATE; RETVAL = Julian(y, m, d) * MINUTES_PER_DAY + ARGV(3); return OK; case 5: if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE || ARG(2).type != INT_TYPE || ARG(3).type != INT_TYPE || ARG(4).type != INT_TYPE) return E_BAD_TYPE; y = ARGV(0); m = ARGV(1) - 1; d = ARGV(2); if (!DateOK(y, m, d)) return E_BAD_DATE; if (ARGV(3) < 0 || ARGV(4) < 0) return E_2LOW; if (ARGV(3) > 23 || ARGV(4) > 59) return E_2HIGH; RETVAL = Julian(y, m, d) * MINUTES_PER_DAY + ARGV(3) * 60 + ARGV(4); return OK; default: return E_2MANY_ARGS; } } /***************************************************************/ /* */ /* FCoerce - type coercion function. */ /* */ /***************************************************************/ static int FCoerce(func_info *info) { char const *s; ASSERT_TYPE(0, STR_TYPE); s = ARGSTR(0); /* Copy the value of ARG(1) into RetVal, and make ARG(1) invalid so it won't be destroyed */ DCOPYVAL(RetVal, ARG(1)); if (! StrCmpi(s, "int")) return DoCoerce(INT_TYPE, &RetVal); else if (! StrCmpi(s, "date")) return DoCoerce(DATE_TYPE, &RetVal); else if (! StrCmpi(s, "time")) return DoCoerce(TIME_TYPE, &RetVal); else if (! StrCmpi(s, "string")) return DoCoerce(STR_TYPE, &RetVal); else if (! StrCmpi(s, "datetime")) return DoCoerce(DATETIME_TYPE, &RetVal); else return E_CANT_COERCE; } /***************************************************************/ /* */ /* FMax - select maximum from a list of args. */ /* */ /***************************************************************/ static int FMax(func_info *info) { Value *maxptr; int i; char type; maxptr = &ARG(0); type = maxptr->type; for (i=1; i maxptr->v.val) maxptr = &ARG(i); } else { if (strcmp(ARG(i).v.str, maxptr->v.str) > 0) maxptr = &ARG(i); } } DCOPYVAL(RetVal, *maxptr); return OK; } /***************************************************************/ /* */ /* FMin - select minimum from a list of args. */ /* */ /***************************************************************/ static int FMin(func_info *info) { Value *minptr; int i; char type; minptr = &ARG(0); type = minptr->type; for (i=1; iv.val) minptr = &ARG(i); } else { if (strcmp(ARG(i).v.str, minptr->v.str) < 0) minptr = &ARG(i); } } DCOPYVAL(RetVal, *minptr); return OK; } /***************************************************************/ /* */ /* FAsc - ASCII value of first char of string */ /* */ /***************************************************************/ static int FAsc(func_info *info) { ASSERT_TYPE(0, STR_TYPE); RetVal.type = INT_TYPE; RETVAL = *(ARGSTR(0)); return OK; } /***************************************************************/ /* */ /* FChar - build a string from ASCII values */ /* */ /***************************************************************/ static int FChar(func_info *info) { int i, len; /* Special case of one arg - if given ascii value 0, create empty string */ if (Nargs == 1) { ASSERT_TYPE(0, INT_TYPE); if (ARGV(0) < -128) return E_2LOW; if (ARGV(0) > 255) return E_2HIGH; len = ARGV(0) ? 2 : 1; RetVal.v.str = malloc(len); if (!RetVal.v.str) return E_NO_MEM; RetVal.type = STR_TYPE; *(RetVal.v.str) = ARGV(0); if (len>1) *(RetVal.v.str + 1) = 0; return OK; } RetVal.v.str = malloc(Nargs + 1); if (!RetVal.v.str) return E_NO_MEM; RetVal.type = STR_TYPE; for (i=0; i 255) { free(RetVal.v.str); RetVal.type = ERR_TYPE; return E_2HIGH; } *(RetVal.v.str + i) = ARG(i).v.val; } *(RetVal.v.str + Nargs) = 0; return OK; } /***************************************************************/ /* */ /* Functions for extracting the components of a date. */ /* */ /* FDay - get day of month */ /* FMonnum - get month (1-12) */ /* FYear - get year */ /* FWkdaynum - get weekday num (0 = Sun) */ /* FWkday - get weekday (string) */ /* FMon - get month (string) */ /* */ /***************************************************************/ static int FDay(func_info *info) { int y, m, d, v; if (!HASDATE(ARG(0))) return E_BAD_TYPE; v = DATEPART(ARG(0)); if (v == CacheJul) d = CacheDay; else { FromJulian(v, &y, &m, &d); CacheJul = v; CacheYear = y; CacheMon = m; CacheDay = d; } RetVal.type = INT_TYPE; RETVAL = d; return OK; } static int FMonnum(func_info *info) { int y, m, d, v; if (!HASDATE(ARG(0))) return E_BAD_TYPE; v = DATEPART(ARG(0)); if (v == CacheJul) m = CacheMon; else { FromJulian(v, &y, &m, &d); CacheJul = v; CacheYear = y; CacheMon = m; CacheDay = d; } RetVal.type = INT_TYPE; RETVAL = m+1; return OK; } static int FYear(func_info *info) { int y, m, d, v; if (!HASDATE(ARG(0))) return E_BAD_TYPE; v = DATEPART(ARG(0)); if (v == CacheJul) y = CacheYear; else { FromJulian(v, &y, &m, &d); CacheJul = v; CacheYear = y; CacheMon = m; CacheDay = d; } RetVal.type = INT_TYPE; RETVAL = y; return OK; } static int FWkdaynum(func_info *info) { int v; if (!HASDATE(ARG(0))) return E_BAD_TYPE; v = DATEPART(ARG(0)); RetVal.type = INT_TYPE; /* Correct so that 0 = Sunday */ RETVAL = (v+1) % 7; return OK; } static int FWkday(func_info *info) { char const *s; if (!HASDATE(ARG(0)) && ARG(0).type != INT_TYPE) return E_BAD_TYPE; if (ARG(0).type == INT_TYPE) { if (ARGV(0) < 0) return E_2LOW; if (ARGV(0) > 6) return E_2HIGH; /* Convert 0=Sun to 0=Mon */ ARGV(0)--; if (ARGV(0) < 0) ARGV(0) = 6; s = DayName[ARGV(0)]; } else s = DayName[DATEPART(ARG(0)) % 7]; return RetStrVal(s, info); } static int FMon(func_info *info) { char const *s; int y, m, d, v; if (!HASDATE(ARG(0)) && ARG(0).type != INT_TYPE) return E_BAD_TYPE; if (ARG(0).type == INT_TYPE) { m = ARGV(0) - 1; if (m < 0) return E_2LOW; if (m > 11) return E_2HIGH; } else { v = DATEPART(ARG(0)); if (v == CacheJul) m = CacheMon; else { FromJulian(v, &y, &m, &d); CacheJul = v; CacheYear = y; CacheMon = m; CacheDay = d; } } s = MonthName[m]; return RetStrVal(s, info); } /***************************************************************/ /* */ /* FHour - extract hour from a time */ /* FMinute - extract minute from a time */ /* FTime - create a time from hour and minute */ /* */ /***************************************************************/ static int FHour(func_info *info) { int v; if (!HASTIME(ARG(0))) return E_BAD_TYPE; v = TIMEPART(ARG(0)); RetVal.type = INT_TYPE; RETVAL = v / 60; return OK; } static int FMinute(func_info *info) { int v; if (!HASTIME(ARG(0))) return E_BAD_TYPE; v = TIMEPART(ARG(0)); RetVal.type = INT_TYPE; RETVAL = v % 60; return OK; } static int FTime(func_info *info) { int h, m; if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE; h = ARGV(0); m = ARGV(1); if (h<0 || m<0) return E_2LOW; if (h>23 || m>59) return E_2HIGH; RetVal.type = TIME_TYPE; RETVAL = h*60 + m; return OK; } /***************************************************************/ /* */ /* FAbs - absolute value */ /* FSgn - signum function */ /* */ /***************************************************************/ static int FAbs(func_info *info) { int v; ASSERT_TYPE(0, INT_TYPE); v = ARGV(0); RetVal.type = INT_TYPE; RETVAL = (v < 0) ? (-v) : v; return OK; } static int FSgn(func_info *info) { int v; ASSERT_TYPE(0, INT_TYPE); v = ARGV(0); RetVal.type = INT_TYPE; if (v>0) RETVAL = 1; else if (v<0) RETVAL = -1; else RETVAL = 0; return OK; } /***************************************************************/ /* */ /* FOrd - returns a string containing ordinal number. */ /* */ /* EG - ord(2) == "2nd", etc. */ /* */ /***************************************************************/ static int FOrd(func_info *info) { int t, u, v; char const *s; char buf[32]; ASSERT_TYPE(0, INT_TYPE); v = ARGV(0); t = v % 100; if (t < 0) t = -t; u = t % 10; s = "th"; if (u == 1 && t != 11) s = "st"; if (u == 2 && t != 12) s = "nd"; if (u == 3 && t != 13) s = "rd"; sprintf(buf, "%d%s", v, s); return RetStrVal(buf, info); } /***************************************************************/ /* */ /* FPlural - pluralization function */ /* */ /* plural(n) --> "" or "s" */ /* plural(n, str) --> "str" or "strs" */ /* plural(n, str1, str2) --> "str1" or "str2" */ /* */ /***************************************************************/ static int FPlural(func_info *info) { ASSERT_TYPE(0, INT_TYPE); switch(Nargs) { case 1: if (ARGV(0) == 1) return RetStrVal("", info); else return RetStrVal("s", info); case 2: ASSERT_TYPE(1, STR_TYPE); if (ARGV(0) == 1) { DCOPYVAL(RetVal, ARG(1)); return OK; } RetVal.type = STR_TYPE; RetVal.v.str = malloc(strlen(ARGSTR(1))+2); if (!RetVal.v.str) { RetVal.type = ERR_TYPE; return E_NO_MEM; } strcpy(RetVal.v.str, ARGSTR(1)); strcat(RetVal.v.str, "s"); return OK; default: if (ARG(1).type != STR_TYPE || ARG(2).type != STR_TYPE) return E_BAD_TYPE; if (ARGV(0) == 1) DCOPYVAL(RetVal, ARG(1)); else DCOPYVAL(RetVal, ARG(2)); return OK; } } /***************************************************************/ /* */ /* FChoose */ /* Choose the nth value from a list of value. If n<1, choose */ /* first. If n>N, choose Nth value. Indexes always start */ /* from 1. */ /* */ /***************************************************************/ static int FChoose(func_info *info) { int v; ASSERT_TYPE(0, INT_TYPE); v = ARGV(0); if (v < 1) v = 1; if (v > Nargs-1) v = Nargs-1; DCOPYVAL(RetVal, ARG(v)); return OK; } /***************************************************************/ /* */ /* FVersion - version of Remind */ /* */ /***************************************************************/ static int FVersion(func_info *info) { return RetStrVal(VERSION, info); } /***************************************************************/ /* */ /* FOstype - the type of operating system */ /* (UNIX, OS/2, or MSDOS) */ /* */ /***************************************************************/ static int FOstype(func_info *info) { return RetStrVal("UNIX", info); } /***************************************************************/ /* */ /* FUpper - convert string to upper-case */ /* FLower - convert string to lower-case */ /* */ /***************************************************************/ static int FUpper(func_info *info) { char *s; ASSERT_TYPE(0, STR_TYPE); DCOPYVAL(RetVal, ARG(0)); s = RetVal.v.str; while (*s) { *s = UPPER(*s); s++; } return OK; } static int FLower(func_info *info) { char *s; ASSERT_TYPE(0, STR_TYPE); DCOPYVAL(RetVal, ARG(0)); s = RetVal.v.str; while (*s) { *s = LOWER(*s); s++; } return OK; } /***************************************************************/ /* */ /* FToday - return the system's notion of "today" */ /* Frealtoday - return today's date as read from OS. */ /* FNow - return the system time (or time on cmd line.) */ /* FRealnow - return the true system time */ /* */ /***************************************************************/ static int FToday(func_info *info) { RetVal.type = DATE_TYPE; RETVAL = JulianToday; return OK; } static int FRealtoday(func_info *info) { RetVal.type = DATE_TYPE; RETVAL = RealToday; return OK; } static int FNow(func_info *info) { RetVal.type = TIME_TYPE; RETVAL = (int) ( SystemTime(0) / 60L ); return OK; } static int FRealnow(func_info *info) { RetVal.type = TIME_TYPE; RETVAL = (int) ( SystemTime(1) / 60L ); return OK; } static int FCurrent(func_info *info) { RetVal.type = DATETIME_TYPE; RETVAL = JulianToday * MINUTES_PER_DAY + (SystemTime(0) / 60); return OK; } static int FRealCurrent(func_info *info) { RetVal.type = DATETIME_TYPE; RETVAL = RealToday * MINUTES_PER_DAY + (SystemTime(1) / 60); return OK; } /***************************************************************/ /* */ /* FGetenv - get the value of an environment variable. */ /* */ /***************************************************************/ static int FGetenv(func_info *info) { ASSERT_TYPE(0, STR_TYPE); return RetStrVal(getenv(ARGSTR(0)), info); } /***************************************************************/ /* */ /* FValue */ /* */ /* Get the value of a variable. If a second arg is supplied, */ /* it is returned if variable is undefined. */ /* */ /***************************************************************/ static int FValue(func_info *info) { Var *v; ASSERT_TYPE(0, STR_TYPE); switch(Nargs) { case 1: return GetVarValue(ARGSTR(0), &RetVal, NULL, NULL); case 2: v = FindVar(ARGSTR(0), 0); if (!v) { DCOPYVAL(RetVal, ARG(1)); return OK; } else { return CopyValue(&RetVal, &v->v); } } return OK; } /***************************************************************/ /* */ /* FDefined */ /* */ /* Return 1 if a variable is defined, 0 if it is not. */ /* */ /***************************************************************/ static int FDefined(func_info *info) { ASSERT_TYPE(0, STR_TYPE); RetVal.type = INT_TYPE; if (FindVar(ARGSTR(0), 0)) RETVAL = 1; else RETVAL = 0; return OK; } /***************************************************************/ /* */ /* FTrigdate and FTrigtime */ /* */ /* Date and time of last trigger. These are stored in global */ /* vars. */ /* */ /***************************************************************/ static int FTrigdate(func_info *info) { if (LastTrigValid) { RetVal.type = DATE_TYPE; RETVAL = LastTriggerDate; } else { RetVal.type = INT_TYPE; RETVAL = 0; } return OK; } static int FTrigvalid(func_info *info) { RetVal.type = INT_TYPE; RETVAL = LastTrigValid; return OK; } static int FTrigtime(func_info *info) { if (LastTriggerTime != NO_TIME) { RetVal.type = TIME_TYPE; RETVAL = LastTriggerTime; } else { RetVal.type = INT_TYPE; RETVAL = 0; } return OK; } static int FTrigdatetime(func_info *info) { if (!LastTrigValid) { RetVal.type = INT_TYPE; RETVAL = 0; } else if (LastTriggerTime != NO_TIME) { RetVal.type = DATETIME_TYPE; RETVAL = LastTriggerDate * MINUTES_PER_DAY + LastTriggerTime; } else { RetVal.type = DATE_TYPE; RETVAL = LastTriggerDate; } return OK; } /***************************************************************/ /* */ /* FDaysinmon */ /* */ /* Returns the number of days in mon,yr */ /* */ /***************************************************************/ static int FDaysinmon(func_info *info) { if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE; if (ARGV(0) > 12 || ARGV(0) < 1 || ARGV(1) < BASE || ARGV(1) > BASE+YR_RANGE) return E_DOMAIN_ERR; RetVal.type = INT_TYPE; RETVAL = DaysInMonth(ARGV(0)-1, ARGV(1)); return OK; } /***************************************************************/ /* */ /* FIsleap */ /* */ /* Return 1 if year is a leap year, zero otherwise. */ /* */ /***************************************************************/ static int FIsleap(func_info *info) { int y, m, d; if (ARG(0).type != INT_TYPE && !HASDATE(ARG(0))) return E_BAD_TYPE; /* If it's a date, extract the year */ if (HASDATE(ARG(0))) FromJulian(DATEPART(ARG(0)), &y, &m, &d); else y = ARGV(0); RetVal.type = INT_TYPE; RETVAL = IsLeapYear(y); return OK; } /***************************************************************/ /* */ /* FTrigger */ /* */ /* Put out a date in a format suitable for triggering. */ /* */ /***************************************************************/ static int FTrigger(func_info *info) { int y, m, d; int date, tim; char buf[128]; tim = NO_TIME; if (ARG(0).type != DATE_TYPE && ARG(0).type != DATETIME_TYPE) return E_BAD_TYPE; if (ARG(0).type == DATE_TYPE) { date = ARGV(0); } else { date = ARGV(0) / MINUTES_PER_DAY; tim = ARGV(0) % MINUTES_PER_DAY; } if (ARG(0).type == DATE_TYPE) { if (Nargs > 2) { /* Date Time UTCFlag */ if (ARG(0).type == DATETIME_TYPE) return E_BAD_TYPE; ASSERT_TYPE(2, INT_TYPE); ASSERT_TYPE(1, TIME_TYPE); tim = ARGV(1); if (ARGV(2)) { UTCToLocal(date, tim, &date, &tim); } } else if (Nargs > 1) { /* Date Time */ ASSERT_TYPE(1, TIME_TYPE); tim = ARGV(1); } } else { if (Nargs > 2) { return E_2MANY_ARGS; } else if (Nargs > 1) { /* DateTime UTCFlag */ ASSERT_TYPE(1, INT_TYPE); if (ARGV(1)) { UTCToLocal(date, tim, &date, &tim); } } } FromJulian(date, &y, &m, &d); if (tim != NO_TIME) { sprintf(buf, "%d %s %d AT %02d:%02d", d, EnglishMonthName[m], y, tim/60, tim%60); } else { sprintf(buf, "%d %s %d", d, EnglishMonthName[m], y); } return RetStrVal(buf, info); } /***************************************************************/ /* */ /* FShell */ /* */ /* The shell function. */ /* */ /* If run is disabled, will not be executed. */ /* */ /***************************************************************/ static int FShell(func_info *info) { DynamicBuffer buf; int ch, r; FILE *fp; /* For compatibility with previous versions of Remind, which used a static buffer for reading results from shell() command */ int maxlen = 511; DBufInit(&buf); if (RunDisabled) return E_RUN_DISABLED; ASSERT_TYPE(0, STR_TYPE); if (Nargs >= 2) { ASSERT_TYPE(1, INT_TYPE); maxlen = ARGV(1); } fp = popen(ARGSTR(0), "r"); if (!fp) return E_IO_ERR; while (1) { ch = getc(fp); if (ch == EOF) { break; } if (isspace(ch)) ch = ' '; if (DBufPutc(&buf, (char) ch) != OK) { pclose(fp); DBufFree(&buf); return E_NO_MEM; } if (maxlen > 0 && DBufLen(&buf) >= maxlen) { break; } } /* Delete trailing newline (converted to space) */ if (DBufLen(&buf) && DBufValue(&buf)[DBufLen(&buf)-1] == ' ') { DBufValue(&buf)[DBufLen(&buf)-1] = 0; } /* XXX Should we consume remaining output from cmd? */ pclose(fp); r = RetStrVal(DBufValue(&buf), info); DBufFree(&buf); return r; } /***************************************************************/ /* */ /* FIsomitted */ /* */ /* Is a date omitted? */ /* */ /***************************************************************/ static int FIsomitted(func_info *info) { int r; if (!HASDATE(ARG(0))) return E_BAD_TYPE; RetVal.type = INT_TYPE; r = IsOmitted(DATEPART(ARG(0)), 0, NULL, &RETVAL); return r; } /***************************************************************/ /* */ /* FSubstr */ /* */ /* The substr function. We destroy the value on the stack. */ /* */ /***************************************************************/ static int FSubstr(func_info *info) { char *s; char const *t; int start, end; if (ARG(0).type != STR_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE; if (Nargs == 3 && ARG(2).type != INT_TYPE) return E_BAD_TYPE; s = ARGSTR(0); start = 1; while (start < ARGV(1)) { if (!*s) break; s++; start++; } if (Nargs == 2 || !*s) return RetStrVal(s, info); end = start; t = s; while (end <= ARGV(2)) { if (!*s) break; s++; end++; } *s = 0; return RetStrVal(t, info); } /***************************************************************/ /* */ /* FIndex */ /* */ /* The index of one string embedded in another. */ /* */ /***************************************************************/ static int FIndex(func_info *info) { char const *s; int start; if (ARG(0).type != STR_TYPE || ARG(1).type != STR_TYPE || (Nargs == 3 && ARG(2).type != INT_TYPE)) return E_BAD_TYPE; s = ARGSTR(0); /* If 3 args, bump up the start */ if (Nargs == 3) { start = 1; while (start < ARGV(2)) { if (!*s) break; s++; start++; } } /* Find the string */ s = strstr(s, ARGSTR(1)); RetVal.type = INT_TYPE; if (!s) { RETVAL = 0; return OK; } RETVAL = (s - ARGSTR(0)) + 1; return OK; } /***************************************************************/ /* */ /* FIif */ /* */ /* The IIF function. */ /* */ /***************************************************************/ static int FIif(func_info *info) { int istrue; int arg; if (!(Nargs % 2)) return E_IIF_ODD; for (arg=0; arg DBufValue(&buf) && *s != '/') s--; if (*s == '/') { *s = 0; r = RetStrVal(DBufValue(&buf), info); } else r = RetStrVal(".", info); DBufFree(&buf); return r; } /***************************************************************/ /* */ /* FAccess */ /* */ /* The UNIX access() system call. */ /* */ /***************************************************************/ static int FAccess(func_info *info) { int amode; char const *s; if (ARG(0).type != STR_TYPE || (ARG(1).type != INT_TYPE && ARG(1).type != STR_TYPE)) return E_BAD_TYPE; if (ARG(1).type == INT_TYPE) amode = ARGV(1); else { amode = 0; s = ARGSTR(1); while (*s) { switch(*s++) { case 'r': case 'R': amode |= R_OK; break; case 'w': case 'W': amode |= W_OK; break; case 'x': case 'X': amode |= X_OK; break; } } } RetVal.type = INT_TYPE; RETVAL = access(ARGSTR(0), amode); return OK; } /***************************************************************/ /* */ /* FTypeof */ /* */ /* Implement the typeof() function. */ /* */ /***************************************************************/ static int FTypeof(func_info *info) { switch(ARG(0).type) { case INT_TYPE: return RetStrVal("INT", info); case DATE_TYPE: return RetStrVal("DATE", info); case TIME_TYPE: return RetStrVal("TIME", info); case STR_TYPE: return RetStrVal("STRING", info); case DATETIME_TYPE: return RetStrVal("DATETIME", info); default: return RetStrVal("ERR", info); } } /***************************************************************/ /* */ /* FLanguage */ /* */ /* Implement the language() function. */ /* */ /***************************************************************/ static int FLanguage(func_info *info) { return RetStrVal(L_LANGNAME, info); } /***************************************************************/ /* */ /* FArgs */ /* */ /* Implement the args() function. */ /* */ /***************************************************************/ static int FArgs(func_info *info) { ASSERT_TYPE(0, STR_TYPE); RetVal.type = INT_TYPE; RETVAL = UserFuncExists(ARGSTR(0)); return OK; } /***************************************************************/ /* */ /* FDosubst */ /* */ /* Implement the dosubst() function. */ /* */ /***************************************************************/ static int FDosubst(func_info *info) { int jul, tim, r; DynamicBuffer buf; DBufInit(&buf); jul = NO_DATE; tim = NO_TIME; ASSERT_TYPE(0, STR_TYPE); if (Nargs >= 2) { if (ARG(1).type == DATETIME_TYPE) { jul = DATEPART(ARG(1)); tim = TIMEPART(ARG(1)); } else { ASSERT_TYPE(1, DATE_TYPE); jul = ARGV(1); } if (Nargs >= 3) { if (ARG(1).type == DATETIME_TYPE) { return E_2MANY_ARGS; } ASSERT_TYPE(2, TIME_TYPE); tim = ARGV(2); } } if ((r=DoSubstFromString(ARGSTR(0), &buf, jul, tim))) return r; r = RetStrVal(DBufValue(&buf), info); DBufFree(&buf); return r; } /***************************************************************/ /* */ /* FHebdate */ /* FHebday */ /* FHebmon */ /* FHebyear */ /* */ /* Hebrew calendar support functions */ /* */ /***************************************************************/ static int FHebdate(func_info *info) { int year, day, mon, jahr; int mout, dout; int ans, r; int adarbehave; if (ARG(0).type != INT_TYPE || ARG(1).type != STR_TYPE) return E_BAD_TYPE; day = ARGV(0); mon = HebNameToNum(ARGSTR(1)); if (mon < 0) return E_BAD_HEBDATE; if (Nargs == 2) { r = GetNextHebrewDate(JulianToday, mon, day, 0, 0, &ans); if (r) return r; RetVal.type = DATE_TYPE; RETVAL = ans; return OK; } if (Nargs == 5) { ASSERT_TYPE(4, INT_TYPE); adarbehave = ARGV(4); if (adarbehave < 0) return E_2LOW; if (adarbehave > 2) return E_2HIGH; } else adarbehave = 0; if (Nargs >= 4) { ASSERT_TYPE(3, INT_TYPE); jahr = ARGV(3); if (jahr < 0) return E_2LOW; if (jahr > 2) { r = ComputeJahr(jahr, mon, day, &jahr); if (r) return r; } } else jahr = 0; if (ARG(2).type == INT_TYPE) { year = ARGV(2); r = GetValidHebDate(year, mon, day, 0, &mout, &dout, jahr); if (r) return r; r = HebToJul(year, mout, dout); if (r<0) return E_DATE_OVER; RETVAL = r; RetVal.type = DATE_TYPE; return OK; } else if (HASDATE(ARG(2))) { r = GetNextHebrewDate(DATEPART(ARG(2)), mon, day, jahr, adarbehave, &ans); if (r) return r; RETVAL = ans; RetVal.type = DATE_TYPE; return OK; } else return E_BAD_TYPE; } static int FHebday(func_info *info) { int y, m, d, v; if (!HASDATE(ARG(0))) return E_BAD_TYPE; v = DATEPART(ARG(0)); if (v == CacheHebJul) d = CacheHebDay; else { JulToHeb(v, &y, &m, &d); CacheHebJul = v; CacheHebYear = y; CacheHebMon = m; CacheHebDay = d; } RetVal.type = INT_TYPE; RETVAL = d; return OK; } static int FHebmon(func_info *info) { int y, m, d, v; if (!HASDATE(ARG(0))) return E_BAD_TYPE; v = DATEPART(ARG(0)); if (v == CacheHebJul) { m = CacheHebMon; y = CacheHebYear; } else { JulToHeb(v, &y, &m, &d); CacheHebJul = v; CacheHebYear = y; CacheHebMon = m; CacheHebDay = d; } return RetStrVal(HebMonthName(m, y), info); } static int FHebyear(func_info *info) { int y, m, d, v; if (!HASDATE(ARG(0))) return E_BAD_TYPE; v = DATEPART(ARG(0)); if (v == CacheHebJul) y = CacheHebYear; else { JulToHeb(v, &y, &m, &d); CacheHebJul = v; CacheHebYear = y; CacheHebMon = m; CacheHebDay = d; } RetVal.type = INT_TYPE; RETVAL = y; return OK; } /****************************************************************/ /* */ /* FEasterdate - calc. easter Sunday from a year. */ /* */ /* from The Art of Computer Programming Vol 1. */ /* Fundamental Algorithms */ /* by Donald Knuth. */ /* */ /* Donated by Michael Salmon - thanks! */ /* */ /* I haven't examined this in detail, but I *think* int */ /* arithmetic is fine, even on 16-bit machines. */ /* */ /****************************************************************/ static int FEasterdate(func_info *info) { int y, m, d; int g, c, x, z, e, n; if (ARG(0).type == INT_TYPE) { y = ARGV(0); if (y < BASE) return E_2LOW; else if (y > BASE+YR_RANGE) return E_2HIGH; } else if (HASDATE(ARG(0))) { FromJulian(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */ } else return E_BAD_TYPE; do { g = (y % 19) + 1; /* golden number */ c = (y / 100) + 1; /* century */ x = (3 * c)/4 - 12; /* correction for non-leap year centuries */ z = (8 * c + 5)/25 - 5; /* special constant for moon sync */ d = (5 * y)/4 - x - 10; /* find sunday */ e = (11 * g + 20 + z - x) % 30; /* calc epact */ if ( e < 0 ) e += 30; if ( e == 24 || (e == 25 && g > 11)) e++; n = 44 - e; /* find full moon */ if ( n < 21 ) n += 30; /* after 21st */ d = n + 7 - (d + n)%7; /* calc sunday after */ if (d <= 31) m = 2; else { d = d - 31; m = 3; } RetVal.type = DATE_TYPE; RETVAL = Julian(y, m, d); y++; } while (HASDATE(ARG(0)) && RETVAL < DATEPART(ARG(0))); return OK; } /***************************************************************/ /* */ /* FIsdst and FMinsfromutc */ /* */ /* Check whether daylight saving time is in effect, and */ /* get minutes from UTC. */ /* */ /***************************************************************/ static int FTimeStuff (int wantmins, func_info *info); static int FIsdst(func_info *info) { return FTimeStuff(0, info); } static int FMinsfromutc(func_info *info) { return FTimeStuff(1, info); } static int FTimeStuff(int wantmins, func_info *info) { int jul, tim; int mins, dst; jul = JulianToday; tim = 0; if (Nargs >= 1) { if (!HASDATE(ARG(0))) return E_BAD_TYPE; jul = DATEPART(ARG(0)); if (HASTIME(ARG(0))) { tim = TIMEPART(ARG(0)); } if (Nargs >= 2) { if (HASTIME(ARG(0))) return E_2MANY_ARGS; ASSERT_TYPE(1, TIME_TYPE); tim = ARGV(1); } } if (CalcMinsFromUTC(jul, tim, &mins, &dst)) return E_MKTIME_PROBLEM; RetVal.type = INT_TYPE; if (wantmins) RETVAL = mins; else RETVAL = dst; return OK; } /***************************************************************/ /* */ /* Sunrise and sunset functions. */ /* */ /* Algorithm from "Almanac for computers for the year 1978" */ /* by L. E. Doggett, Nautical Almanac Office, USNO. */ /* */ /* This code also uses some ideas found in programs written */ /* by Michael Schwartz and Marc T. Kaufman. */ /* */ /***************************************************************/ #ifdef PI #undef PI #endif #define PI 3.14159265358979323846 #define DEGRAD (PI/180.0) #define RADDEG (180.0/PI) static int SunStuff(int rise, double cosz, int jul) { int mins, hours; int year, mon, day; double M, L, sinDelta, cosDelta, a, a_hr, cosH, t, H, T; double latitude, longdeg, UT, local; /* Get offset from UTC */ if (CalculateUTC) { if (CalcMinsFromUTC(jul, 12*60, &mins, NULL)) { Eprint(ErrMsg[E_MKTIME_PROBLEM]); return NO_TIME; } } else mins = MinsFromUTC; /* Get latitude and longitude */ longdeg = (double) LongDeg + (double) LongMin / 60.0 + (double) LongSec / 3600.0; latitude = DEGRAD * ((double) LatDeg + (double) LatMin / 60.0 + (double) LatSec / 3600.0); FromJulian(jul, &year, &mon, &day); if (rise > 1) rise -= 2; /* Following formula on page B6 exactly... */ t = (double) jul; if (rise) { t += (6.0 + longdeg/15.0) / 24.0; } else { t += (18.0 + longdeg/15.0) / 24.0; } /* Mean anomaly of sun starting from 1 Jan 1990 */ /* NOTE: This assumes that BASE = 1990!!! */ #if BASE != 1990 #error Sun calculations assume a BASE of 1990! #endif t = 0.9856002585 * t; M = t + 357.828757; /* In degrees */ /* Make sure M is in the range [0, 360) */ M -= (floor(M/360.0) * 360.0); /* Sun's true longitude */ L = M + 1.916*sin(DEGRAD*M) + 0.02*sin(2*DEGRAD*M) + 283.07080214; if (L > 360.0) L -= 360.0; /* Tan of sun's right ascension */ a = RADDEG * atan2(0.91746*sin(DEGRAD*L), cos(DEGRAD*L)); if (a<0) { a += 360.0; } a_hr = a / 15.0; /* Sine of sun's declination */ sinDelta = 0.39782 * sin(DEGRAD*L); cosDelta = sqrt(1 - sinDelta*sinDelta); /* Cosine of sun's local hour angle */ cosH = (cosz - sinDelta * sin(latitude)) / (cosDelta * cos(latitude)); if (cosH < -1.0) { /* Summer -- permanent daylight */ if (rise) return NO_TIME; else return -NO_TIME; } if (cosH > 1.0) { /* Winter -- permanent darkness */ if (rise) return -NO_TIME; else return NO_TIME; } H = RADDEG * acos(cosH); if (rise) H = 360.0 - H; t -= 360.0*floor(t/360.0); T = (H-t) / 15.0 + a_hr - 6.726637276; if (T >= 24.0) T -= 24.0; else if (T < 0.0) T+= 24.0; UT = T + longdeg / 15.0; local = UT + (double) mins / 60.0; if (local < 0.0) local += 24.0; else if (local >= 24.0) local -= 24.0; /* Round off local time to nearest minute */ local = floor(local * 60.0 + 0.5) / 60.0; hours = (int) local; mins = (int) ((local - hours) * 60.0); /* Sometimes, we get roundoff error. Check for "reasonableness" of answer. */ if (rise) { /* Sunrise so close to midnight it wrapped around -- permament light */ if (hours >= 23) return NO_TIME; } else { /* Sunset so close to midnight it wrapped around -- permament light */ if (hours <= 1) return -NO_TIME; } return hours*60 + mins; } /***************************************************************/ /* */ /* Sunrise and Sunset functions. */ /* */ /***************************************************************/ static int FSun(int rise, func_info *info) { int jul = JulianToday; double cosz = -0.014543897; /* for sunrise and sunset */ int r; /* Civil twilight: cos(96 degrees) */ if (rise == 2 || rise == 3) { cosz = -0.104528463268; } if (Nargs >= 1) { if (!HASDATE(ARG(0))) return E_BAD_TYPE; jul = DATEPART(ARG(0)); } r = SunStuff(rise, cosz, jul); if (r == NO_TIME) { RETVAL = 0; RetVal.type = INT_TYPE; } else if (r == -NO_TIME) { RETVAL = MINUTES_PER_DAY; RetVal.type = INT_TYPE; } else { RETVAL = r; RetVal.type = TIME_TYPE; } return OK; } static int FSunrise(func_info *info) { return FSun(1, info); } static int FSunset(func_info *info) { return FSun(0, info); } static int FDawn(func_info *info) { return FSun(3, info); } static int FDusk(func_info *info) { return FSun(2, info); } /***************************************************************/ /* */ /* FFiledate */ /* */ /* Return modification date of a file */ /* */ /***************************************************************/ static int FFiledate(func_info *info) { struct stat statbuf; struct tm *t1; RetVal.type = DATE_TYPE; ASSERT_TYPE(0, STR_TYPE); if (stat(ARGSTR(0), &statbuf)) { RETVAL = 0; return OK; } t1 = localtime(&(statbuf.st_mtime)); if (t1->tm_year + 1900 < BASE) RETVAL=0; else RETVAL=Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday); return OK; } /***************************************************************/ /* */ /* FFiledatetime */ /* */ /* Return modification datetime of a file */ /* */ /***************************************************************/ static int FFiledatetime(func_info *info) { struct stat statbuf; struct tm *t1; RetVal.type = DATETIME_TYPE; ASSERT_TYPE(0, STR_TYPE); if (stat(ARGSTR(0), &statbuf)) { RETVAL = 0; return OK; } t1 = localtime(&(statbuf.st_mtime)); if (t1->tm_year + 1900 < BASE) RETVAL=0; else RETVAL = MINUTES_PER_DAY * Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday) + t1->tm_hour * 60 + t1->tm_min; return OK; } /***************************************************************/ /* */ /* FPsshade */ /* */ /* Canned PostScript code for shading a calendar square */ /* */ /***************************************************************/ static int psshade_warned = 0; static int FPsshade(func_info *info) { char psbuff[256]; char *s = psbuff; int i; /* 1 or 3 args */ if (Nargs != 1 && Nargs != 3) return E_2MANY_ARGS; for (i=0; i 100) return E_2HIGH; } if (!psshade_warned) { psshade_warned = 1; Eprint("psshade() is deprecated; use SPECIAL SHADE instead."); } sprintf(s, "/_A LineWidth 2 div def "); s += strlen(s); sprintf(s, "_A _A moveto "); s += strlen(s); sprintf(s, "BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto "); s += strlen(s); if (Nargs == 1) { sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div setgray fill 0.0 setgray", ARGV(0)); } else { sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div %d 100 div %d 100 div setrgbcolor fill 0.0 setgray", ARGV(0), ARGV(1), ARGV(2)); } return RetStrVal(psbuff, info); } /***************************************************************/ /* */ /* FPsmoon */ /* */ /* Canned PostScript code for generating moon phases */ /* */ /***************************************************************/ static int psmoon_warned = 0; static int FPsmoon(func_info *info) { char psbuff[512]; char sizebuf[30]; char fontsizebuf[30]; char *s = psbuff; char const *extra = NULL; int size = -1; int fontsize = -1; ASSERT_TYPE(0, INT_TYPE); if (ARGV(0) < 0) return E_2LOW; if (ARGV(0) > 3) return E_2HIGH; if (Nargs > 1) { ASSERT_TYPE(1, INT_TYPE); if (ARGV(1) < -1) return E_2LOW; size = ARGV(1); if (Nargs > 2) { ASSERT_TYPE(2, STR_TYPE); extra = ARGSTR(2); if (Nargs > 3) { ASSERT_TYPE(3, INT_TYPE); if (ARGV(3) <= 0) return E_2LOW; fontsize = ARGV(3); } } } if (!psmoon_warned) { psmoon_warned = 1; Eprint("psmoon() is deprecated; use SPECIAL MOON instead."); } if (size > 0) { sprintf(sizebuf, "%d", size); } else { strcpy(sizebuf, "DaySize 2 div"); } if (fontsize > 0) { sprintf(fontsizebuf, "%d", fontsize); } else { strcpy(fontsizebuf, "EntrySize"); } sprintf(s, "gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub", sizebuf, sizebuf); s += strlen(s); sprintf(s, " %s 0 360 arc closepath", sizebuf); s += strlen(s); switch(ARGV(0)) { case 0: sprintf(s, " fill"); s += strlen(s); break; case 2: sprintf(s, " stroke"); s += strlen(s); break; case 1: sprintf(s, " stroke"); s += strlen(s); sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub", sizebuf, sizebuf); s += strlen(s); sprintf(s, " %s 90 270 arc closepath fill", sizebuf); s += strlen(s); break; default: sprintf(s, " stroke"); s += strlen(s); sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub", sizebuf, sizebuf); s += strlen(s); sprintf(s, " %s 270 90 arc closepath fill", sizebuf); s += strlen(s); break; } if (extra) { sprintf(s, " Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto /EntryFont findfont %s scalefont setfont (%s) show", sizebuf, sizebuf, sizebuf, sizebuf, fontsizebuf, extra); s += strlen(s); } sprintf(s, " grestore"); return RetStrVal(psbuff, info); } /***************************************************************/ /* */ /* FMoonphase */ /* */ /* Phase of moon for specified date/time. */ /* */ /***************************************************************/ static int FMoonphase(func_info *info) { int date, time; switch(Nargs) { case 0: date = JulianToday; time = 0; break; case 1: if (!HASDATE(ARG(0))) return E_BAD_TYPE; date = DATEPART(ARG(0)); if (HASTIME(ARG(0))) { time = TIMEPART(ARG(0)); } else { time = 0; } break; case 2: if (ARG(0).type == DATETIME_TYPE) return E_2MANY_ARGS; if (ARG(0).type != DATE_TYPE && ARG(1).type != TIME_TYPE) return E_BAD_TYPE; date = ARGV(0); time = ARGV(1); break; default: return E_SWERR; } RetVal.type = INT_TYPE; RETVAL = MoonPhase(date, time); return OK; } /***************************************************************/ /* */ /* FMoondate */ /* */ /* Hunt for next occurrence of specified moon phase */ /* */ /***************************************************************/ static int MoonStuff (int want_time, func_info *info); static int FMoondate(func_info *info) { return MoonStuff(DATE_TYPE, info); } static int FMoontime(func_info *info) { return MoonStuff(TIME_TYPE, info); } static int FMoondatetime(func_info *info) { return MoonStuff(DATETIME_TYPE, info); } static int MoonStuff(int type_wanted, func_info *info) { int startdate, starttim; int d, t; startdate = JulianToday; starttim = 0; ASSERT_TYPE(0, INT_TYPE); if (ARGV(0) < 0) return E_2LOW; if (ARGV(0) > 3) return E_2HIGH; if (Nargs >= 2) { if (!HASDATE(ARG(1))) return E_BAD_TYPE; startdate = DATEPART(ARG(1)); if (HASTIME(ARG(1))) { starttim = TIMEPART(ARG(1)); } if (Nargs >= 3) { if (HASTIME(ARG(1))) return E_2MANY_ARGS; ASSERT_TYPE(2, TIME_TYPE); starttim = ARGV(2); } } HuntPhase(startdate, starttim, ARGV(0), &d, &t); RetVal.type = type_wanted; switch(type_wanted) { case TIME_TYPE: RETVAL = t; break; case DATE_TYPE: RETVAL = d; break; case DATETIME_TYPE: RETVAL = d * MINUTES_PER_DAY + t; break; default: return E_BAD_TYPE; } return OK; } static int FTimepart(func_info *info) { if (!HASTIME(ARG(0))) return E_BAD_TYPE; RetVal.type = TIME_TYPE; RETVAL = TIMEPART(ARG(0)); return OK; } static int FDatepart(func_info *info) { if (!HASDATE(ARG(0))) return E_BAD_TYPE; RetVal.type = DATE_TYPE; RETVAL = DATEPART(ARG(0)); return OK; } #ifndef HAVE_SETENV /* This is NOT a general-purpose replacement for setenv. It's only * used for the timezone stuff! */ static int setenv(char const *varname, char const *val, int overwrite) { static char tzbuf[256]; if (strcmp(varname, "TZ")) { fprintf(stderr, "built-in setenv can only be used with TZ\n"); abort(); } if (!overwrite) { fprintf(stderr, "built-in setenv must have overwrite=1\n"); abort(); } if (strlen(val) > 250) { return -1; } sprintf(tzbuf, "%s=%s", varname, val); return(putenv(tzbuf)); } #endif #ifndef HAVE_UNSETENV /* This is NOT a general-purpose replacement for unsetenv. It's only * used for the timezone stuff! */ static void unsetenv(char const *varname) { static char tzbuf[8]; if (strcmp(varname, "TZ")) { fprintf(stderr, "built-in unsetenv can only be used with TZ\n"); abort(); } sprintf(tzbuf, "%s", varname); putenv(tzbuf); } #endif /***************************************************************/ /* */ /* FTz */ /* */ /* Conversion between different timezones. */ /* */ /***************************************************************/ static int tz_set_tz(char const *tz) { int r; if (tz == NULL) { unsetenv("TZ"); r = 0; } else { r = setenv("TZ", tz, 1); } tzset(); return r; } static int tz_convert(int year, int month, int day, int hour, int minute, char const *src_tz, char const *tgt_tz, struct tm *tm) { int r; time_t t; struct tm *res; char const *old_tz; /* init tm struct */ tm->tm_sec = 0; tm->tm_min = minute; tm->tm_hour = hour; tm->tm_mday = day; tm->tm_mon = month; tm->tm_year = year - 1900; tm->tm_wday = 0; /* ignored by mktime */ tm->tm_yday = 0; /* ignored by mktime */ tm->tm_isdst = -1; /* information not available */ /* backup old TZ env var */ old_tz = getenv("TZ"); if (tgt_tz == NULL) { tgt_tz = old_tz; } /* set source TZ */ r = tz_set_tz(src_tz); if (r == -1) { return -1; } /* create timestamp in UTC */ t = mktime(tm); if (t == (time_t) -1) { tz_set_tz(old_tz); return -1; } /* set target TZ */ r = tz_set_tz(tgt_tz); if (r == -1) { tz_set_tz(old_tz); return -1; } /* convert to target TZ */ res = localtime_r(&t, tm); /* restore old TZ */ tz_set_tz(old_tz); /* return result */ if (res == NULL) { return -1; } else { return 1; } } static int FTzconvert(func_info *info) { int year, month, day, hour, minute, r; int jul, tim; struct tm tm; if (ARG(0).type != DATETIME_TYPE || ARG(1).type != STR_TYPE) return E_BAD_TYPE; if (Nargs == 3 && ARG(2).type != STR_TYPE) return E_BAD_TYPE; FromJulian(DATEPART(ARG(0)), &year, &month, &day); r = TIMEPART(ARG(0)); hour = r / 60; minute = r % 60; if (Nargs == 2) { r = tz_convert(year, month, day, hour, minute, ARGSTR(1), NULL, &tm); } else { r = tz_convert(year, month, day, hour, minute, ARGSTR(1), ARGSTR(2), &tm); } if (r == -1) return E_CANT_CONVERT_TZ; jul = Julian(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday); tim = tm.tm_hour * 60 + tm.tm_min; RetVal.type = DATETIME_TYPE; RETVAL = jul * MINUTES_PER_DAY + tim; return OK; } static int FSlide(func_info *info) { int r, omit, d, i, localomit, amt; Token tok; if (!HASDATE(ARG(0))) return E_BAD_TYPE; ASSERT_TYPE(1, INT_TYPE); d = DATEPART(ARG(0)); amt = ARGV(1); if (amt > 1000000) return E_2HIGH; if (amt < -1000000) return E_2LOW; localomit = 0; for (i=2; i 0) { while(amt) { d++; r = IsOmitted(d, localomit, NULL,&omit); if (r) return r; if (!omit) amt--; } } else { while(amt) { d--; r = IsOmitted(d, localomit, NULL,&omit); if (r) return r; if (!omit) amt++; } } RetVal.type = DATE_TYPE; RETVAL = d; return OK; } static int FNonomitted(func_info *info) { int d1, d2, ans, localomit, i; int omit, r; Token tok; if (!HASDATE(ARG(0)) || !HASDATE(ARG(1))) { return E_BAD_TYPE; } d1 = DATEPART(ARG(0)); d2 = DATEPART(ARG(1)); if (d2 < d1) return E_2LOW; localomit = 0; for (i=2; i= 1) { if (!HASDATE(ARG(0))) return E_BAD_TYPE; jul = DATEPART(ARG(0)); } if (Nargs >= 2) { ASSERT_TYPE(1, INT_TYPE); if (ARGV(1) < 0) return E_2LOW; if (ARGV(1) > 6) return E_2HIGH; wkstart = ARGV(1); /* Convert 0=Sun to 0=Mon */ wkstart--; if (wkstart < 0) wkstart = 6; if (Nargs >= 3) { ASSERT_TYPE(2, INT_TYPE); if (ARGV(2) < 1) return E_2LOW; if (ARGV(2) > 31) return E_2HIGH; daystart = ARGV(2); } } RetVal.type = INT_TYPE; /* If start day is 7, first week starts after Jan, otherwise after Dec. */ if (daystart <= 7) { monstart = 0; } else { monstart = 11; } FromJulian(jul, &y, &m, &d); /* Try this year */ candidate = Julian(y, monstart, daystart); while((candidate % 7) != wkstart) candidate++; if (candidate <= jul) { RETVAL = ((jul - candidate) / 7) + 1; return OK; } if (y-1 < BASE) return E_DATE_OVER; /* Must be last year */ candidate = Julian(y-1, monstart, daystart); while((candidate % 7) != wkstart) candidate++; if (candidate <= jul) { RETVAL = ((jul - candidate) / 7) + 1; return OK; } if (y-2 < BASE) return E_DATE_OVER; /* Holy cow! */ candidate = Julian(y-2, monstart, daystart); while((candidate % 7) != wkstart) candidate++; RETVAL = ((jul - candidate) / 7) + 1; return OK; } static int FEvalTrig(func_info *info) { Parser p; Trigger trig; TimeTrig tim; int jul, scanfrom; int r; ASSERT_TYPE(0, STR_TYPE); if (Nargs >= 2) { if (!HASDATE(ARG(1))) return E_BAD_TYPE; scanfrom = DATEPART(ARG(1)); } else { scanfrom = NO_DATE; } CreateParser(ARGSTR(0), &p); p.allownested = 0; r = ParseRem(&p, &trig, &tim, 0); if (r) return r; if (trig.typ != NO_TYPE) { FreeTrig(&trig); return E_PARSE_ERR; } if (scanfrom == NO_DATE) { jul = ComputeTrigger(trig.scanfrom, &trig, &r, 0); } else { /* Hokey... */ if (trig.scanfrom != JulianToday) { Eprint("Warning: SCANFROM is ignored in two-argument form of evaltrig()"); } jul = ComputeTrigger(scanfrom, &trig, &r, 0); } FreeTrig(&trig); if (r) return r; if (jul < 0) { RetVal.type = INT_TYPE; RETVAL = jul; } else if (tim.ttime == NO_TIME) { RetVal.type = DATE_TYPE; RETVAL = jul; } else { RetVal.type = DATETIME_TYPE; RETVAL = (MINUTES_PER_DAY * jul) + tim.ttime; } return OK; } remind-03.01.15/src/globals.c0000644000076400007640000000211312514120706013712 0ustar dfsdfs/***************************************************************/ /* */ /* GLOBALS.C */ /* */ /* This file simply instantiates all of the global variables. */ /* */ /* It does this by #defining MK_GLOBALS and #including */ /* globals.h and err.h */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include /* For defintion of FILE - sigh! */ #include "types.h" #include "custom.h" #define MK_GLOBALS #include "globals.h" #include "err.h" remind-03.01.15/src/globals.h0000644000076400007640000001335312514120702013723 0ustar dfsdfs/***************************************************************/ /* */ /* GLOBALS.H */ /* */ /* This function contains declarations of global variables. */ /* They are instantiated in main.c by defining */ /* MK_GLOBALS. Also contains useful macro definitions. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #ifdef MK_GLOBALS #undef EXTERN #define EXTERN #define INIT(var, val) var = val #else #undef EXTERN #define EXTERN extern #define INIT(var, val) var #endif #define MINUTES_PER_DAY 1440 #define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 )) #define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 )) #define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y)) #define DestroyValue(x) (void) (((x).type == STR_TYPE && (x).v.str) ? (free((x).v.str),(x).type = ERR_TYPE) : 0) EXTERN int JulianToday; EXTERN int RealToday; EXTERN int CurDay; EXTERN int CurMon; EXTERN int CurYear; EXTERN int LineNo; EXTERN int FreshLine; EXTERN INIT( char const *MsgCommand, NULL); EXTERN INIT( int ShowAllErrors, 0); EXTERN INIT( int DebugFlag, 0); EXTERN INIT( int DoCalendar, 0); EXTERN INIT( int DoSimpleCalendar, 0); EXTERN INIT( int DoSimpleCalDelta, 0); EXTERN INIT( int DoPrefixLineNo, 0); EXTERN INIT( int MondayFirst, 0); EXTERN INIT( int Iterations, 1); EXTERN INIT( int PsCal, 0); EXTERN INIT( int CalWidth, 80); EXTERN INIT( int CalWeeks, 0); EXTERN INIT( int CalMonths, 0); EXTERN INIT( int Hush, 0); EXTERN INIT( int NextMode, 0); EXTERN INIT( int InfiniteDelta, 0); EXTERN INIT( int DeltaOffset, 0); EXTERN INIT( int RunDisabled, 0); EXTERN INIT( int IgnoreOnce, 0); EXTERN INIT( int SortByTime, 0); EXTERN INIT( int SortByDate, 0); EXTERN INIT( int SortByPrio, 0); EXTERN INIT( int UntimedBeforeTimed, 0); EXTERN INIT( int DefaultPrio, NO_PRIORITY); EXTERN INIT( long SysTime, -1L); EXTERN char const *InitialFile; EXTERN int FileAccessDate; EXTERN INIT( int DontFork, 0); EXTERN INIT( int DontQueue, 0); EXTERN INIT( int NumQueued, 0); EXTERN INIT( int DontIssueAts, 0); EXTERN INIT( int Daemon, 0); EXTERN INIT( char DateSep, DATESEP); EXTERN INIT( char TimeSep, TIMESEP); EXTERN INIT( int SynthesizeTags, 0); EXTERN INIT( int ScFormat, SC_AMPM); EXTERN INIT( int MaxSatIter, 150); EXTERN INIT( int MaxStringLen, MAX_STR_LEN); EXTERN INIT( char *FileName, NULL); EXTERN INIT( int UseStdin, 0); EXTERN INIT( int PurgeMode, 0); EXTERN INIT( int PurgeIncludeDepth, 0); EXTERN FILE *ErrFp; EXTERN INIT( FILE *PurgeFP, NULL); EXTERN INIT( int NumIfs, 0); EXTERN INIT( unsigned int IfFlags, 0); EXTERN INIT( int LastTriggerDate, 0); EXTERN INIT( int LastTrigValid, 0); EXTERN INIT( int LastTriggerTime, 0); EXTERN INIT( int ShouldCache, 0); EXTERN char const *CurLine; EXTERN INIT( int NumTriggered, 0); EXTERN int ArgC; EXTERN char const **ArgV; EXTERN INIT( int CalLines, CAL_LINES); EXTERN INIT( int CalPad, 1); EXTERN INIT( int UseVTChars, 0); EXTERN INIT( int UseUTF8Chars, 0); EXTERN INIT( int UseVTColors, 0); /* Latitude and longitude */ EXTERN INIT( int LatDeg, LAT_DEG); EXTERN INIT( int LatMin, LAT_MIN); EXTERN INIT( int LatSec, LAT_SEC); EXTERN INIT( int LongDeg, LON_DEG); EXTERN INIT( int LongMin, LON_MIN); EXTERN INIT( int LongSec, LON_SEC); EXTERN INIT( char *Location, LOCATION); /* UTC calculation stuff */ EXTERN INIT( int MinsFromUTC, 0); EXTERN INIT( int CalculateUTC, 1); EXTERN INIT( int FoldYear, 0); /* Parameters for formatting MSGF reminders */ EXTERN INIT( int FormWidth, 72); EXTERN INIT( int FirstIndent, 0); EXTERN INIT( int SubsIndent, 0); EXTERN INIT( char *EndSent, ".?!"); EXTERN INIT( char *EndSentIg, "\"')]}>"); /* We need the language stuff here... */ #include "lang.h" #include "dynbuf.h" EXTERN DynamicBuffer Banner; EXTERN DynamicBuffer LineBuffer; EXTERN DynamicBuffer ExprBuf; /* List of months */ EXTERN char *EnglishMonthName[] #ifdef MK_GLOBALS = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} #endif ; #if LANG == ENGLISH #define MonthName EnglishMonthName #else EXTERN char *MonthName[] #ifdef MK_GLOBALS = {L_JAN, L_FEB, L_MAR, L_APR, L_MAY, L_JUN, L_JUL, L_AUG, L_SEP, L_OCT, L_NOV, L_DEC} #endif ; #endif EXTERN char *EnglishDayName[] #ifdef MK_GLOBALS = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} #endif ; #if LANG == ENGLISH #define DayName EnglishDayName #else EXTERN char *DayName[] #ifdef MK_GLOBALS = {L_MONDAY, L_TUESDAY, L_WEDNESDAY, L_THURSDAY, L_FRIDAY, L_SATURDAY, L_SUNDAY} #endif ; #endif EXTERN int MonthDays[] #ifdef MK_GLOBALS = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} #endif ; /* The first day of each month expressed as number of days after Jan 1. Second row is for leap years. */ EXTERN int MonthIndex[2][12] #ifdef MK_GLOBALS = { { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } } #endif ; remind-03.01.15/src/hbcal.c0000644000076400007640000003736412514120673013363 0ustar dfsdfs/***************************************************************/ /* */ /* HBCAL.C */ /* */ /* Support for the Hebrew calendar */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /* Derived from code written by Amos Shapir in 1978; revised */ /* 1985. */ /* */ /***************************************************************/ #include "config.h" #include /* For FILE used by protos.h - sigh. */ #include "types.h" #include "protos.h" #include "globals.h" #include "err.h" #define HOUR 1080L #define DAY (24L*HOUR) #define WEEK (7L*DAY) #define M(h,p) ((long)(h*HOUR+p)) #define MONTH (DAY+M(12,793)) /* Correction to convert base reference to 1990. NOTE: If you change the value of BASE in config.h, this will NOT WORK! You'll have to add the appropriate number of days to CORRECTION. */ #define CORRECTION 732774L #define TISHREY 0 #define HESHVAN 1 #define KISLEV 2 #define TEVET 3 #define SHVAT 4 #define ADARA 5 #define ADARB 6 #define NISAN 7 #define IYAR 8 #define SIVAN 9 #define TAMUZ 10 #define AV 11 #define ELUL 12 #define ADAR 13 #define JAHR_NONE 0 #define JAHR_FORWARD 1 #define JAHR_BACKWARD 2 #define ADAR2ADARB 0 #define ADAR2ADARA 1 #define ADAR2BOTH 2 static char const *HebMonthNames[] = { "Tishrey", "Heshvan", "Kislev", "Tevet", "Shvat", "Adar A", "Adar B", "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul", "Adar"}; static char MaxMonLen[] = { 30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29}; static char HebIsLeap[] = {0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1}; /***************************************************************/ /* */ /* RoshHashana */ /* */ /* Return the Julian date for Rosh Hashana of specified */ /* Hebrew year. (ie, 5751, not 1990) */ /* */ /***************************************************************/ int RoshHashana(int i) { long j; j = DaysToHebYear(i-3744) - CORRECTION; return (int) j; /* No overflow check... very trusting! */ } /***************************************************************/ /* */ /* DaysToHebYear */ /* */ /* Return the number of days to RH of specified Hebrew year */ /* from new moon before Tishrey 1 5701. */ /* */ /***************************************************************/ long DaysToHebYear(int y) { long m, nm, dw, s, l; l = y*7+1; /* no. of leap months */ m = y*12+l/19; /* total no. of months */ nm = m*MONTH+M(1,779); /* molad at 197 cycles */ s = m*28+nm/DAY-2; nm %= WEEK; l %= 19L; dw = nm/DAY; nm %= DAY; /* special cases of Molad Zaken */ if (nm >= 18*HOUR || (l < 12 && dw==3 && nm>=M(9,204)) || (l < 7 && dw==2 && nm>=M(15,589))) s++,dw++; /* ADU */ if(dw == 1 || dw == 4 || dw == 6) s++; return s; } /***************************************************************/ /* */ /* DaysInHebYear */ /* */ /* Return the number of days in the Hebrew year. */ /* */ /* */ /***************************************************************/ int DaysInHebYear(int y) { long thisyear, nextyear; thisyear = DaysToHebYear(y-3744); nextyear = DaysToHebYear(y-3743); return (int) (nextyear - thisyear); } /***************************************************************/ /* */ /* DaysInHebMonths */ /* */ /* Return a pointer to an array giving lengths of months */ /* given the LENGTH of the Hebrew year. */ /* */ /***************************************************************/ char const *DaysInHebMonths(int ylen) { static char monlen[13] = {30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29}; if (ylen > 355) { monlen[ADARA] = 30; ylen -= 30; } else monlen[ADARA] = 0; if (ylen == 353) monlen[KISLEV] = 29; else monlen[KISLEV] = 30; if (ylen == 355) monlen[HESHVAN] = 30; else monlen[HESHVAN] = 29; return monlen; } /***************************************************************/ /* */ /* HebToJul */ /* */ /* Convert a Hebrew date to Julian. */ /* Hebrew months range from 0-12, but Adar A has 0 length in */ /* non-leap-years. */ /* */ /***************************************************************/ int HebToJul(int hy, int hm, int hd) { int ylen; char const *monlens; int rh; int m; /* Do some range checking */ if (hy - 3761 < BASE || hy - 3760 > BASE+YR_RANGE) return -1; ylen = DaysInHebYear(hy); monlens = DaysInHebMonths(ylen); /* Get the Rosh Hashana of the year */ rh = RoshHashana(hy); /* Bump up to the appropriate month */ for (m=0; mjul) y--; /* Got the year - now find the month */ jul -= rh; ylen = DaysInHebYear(y); monlen = DaysInHebMonths(ylen); m = 0; while((jul >= monlen[m]) || !monlen[m]) { jul -= monlen[m]; m++; } *hy = y; *hm = m; *hd = jul+1; } /***************************************************************/ /* */ /* HebNameToNum */ /* */ /* Convert a Hebrew month's name to its number, given the */ /* year. */ /* */ /***************************************************************/ int HebNameToNum(char const *mname) { int i; int m=-1; for (i=0; i<14; i++) if (!StrCmpi(mname, HebMonthNames[i])) { m = i; break; } return m; } /***************************************************************/ /* */ /* HebMonthname */ /* */ /* Convert a Hebrew month's number to its name, given the */ /* year. */ /* */ /***************************************************************/ char const *HebMonthName(int m, int y) { if (m != ADARA && m != ADARB) return HebMonthNames[m]; if (!HebIsLeap[(y-1)%19]) return HebMonthNames[ADAR]; else return HebMonthNames[m]; } /***************************************************************/ /* */ /* GetValidHebDate */ /* */ /* Given the day of a month, a Hebrew month number, and a */ /* year, return a valid year number, month number, and day */ /* number. Returns 0 for success, non-0 for failure. */ /* If *dout is set to -1, then date is completely invalid. */ /* Otherwise, date is only invalid in specified year. */ /* */ /* Algorithm: */ /* - Convert references to Adar to Adar B. */ /* If jahr == 0 then */ /* - If no such date in current Hebrew year, return */ /* failure. */ /* else follow jahrzeit rules: */ /* - If jahr == 1: Convert 30 Kislev to 1 Tevet and */ /* 30 Heshvan to 1 Kislev if chaser. */ /* Convert 30 Adar A to 1 Nisan in nonleap */ /* This rule is NOT appropriate for a */ /* jahrzeit on 30 Adar A. Use rule 2 for */ /* that. However, I believe it is correct */ /* for smachot. */ /* - If jahr == 2: Convert 30 Kislev to 29 Kislev and */ /* 30 Heshvan to 29 Heshvan if chaser. */ /* Change 30 Adar A to 30 Shvat in nonleap */ /* */ /***************************************************************/ int GetValidHebDate(int yin, int min, int din, int adarbehave, int *mout, int *dout, int jahr) { char const *monlen; int ylen; *mout = min; *dout = din; /* Do some error checking */ if (din < 1 || din > MaxMonLen[min] || min < 0 || min > 13) { *dout = -1; return E_BAD_HEBDATE; } ylen = DaysInHebYear(yin); monlen = DaysInHebMonths(ylen); /* Convert ADAR as necessary */ if (min == ADAR) { switch(adarbehave) { case ADAR2ADARA: if (monlen[ADARA]) *mout = min = ADARA; else *mout = min = ADARB; break; case ADAR2ADARB: *mout = min = ADARB; break; default: Eprint("GetValidHebDate: Bad adarbehave value %d", adarbehave); return E_SWERR; } } if (din <= monlen[min]) return OK; switch(jahr) { case JAHR_NONE: return E_BAD_DATE; case JAHR_FORWARD: if (min == KISLEV) { *mout = TEVET; *dout = 1; return OK; } else if (min == HESHVAN) { *mout = KISLEV; *dout = 1; return OK; } else if (min == ADARA) { if (din > 29) { *dout = 1; *mout = NISAN; } else { *dout = din; *mout = ADARB; } return OK; } Eprint("GetValidHebDate: (1) software error! %d", jahr); return E_SWERR; case JAHR_BACKWARD: if (min == KISLEV) { *mout = KISLEV; *dout = 29; return OK; } else if (min == HESHVAN) { *mout = HESHVAN; *dout = 29; return OK; } else if (min == ADARA) { if (din > 29) { *dout = 30; *mout = SHVAT; } else { *mout = ADARB; *dout = din; } return OK; } Eprint("GetValidHebDate: (2) software error! %d", jahr); return E_SWERR; default: Eprint("GetValidHebDate: (3) software error! %d", jahr); return E_SWERR; } } /***************************************************************/ /* */ /* GetNextHebrewDate */ /* */ /* Get the next Hebrew date on or after specified date. */ /* */ /* Returns 0 for success, non-zero for failure. */ /* */ /***************************************************************/ int GetNextHebrewDate(int julstart, int hm, int hd, int jahr, int adarbehave, int *ans) { int r, yout, mout, dout, jul=1; int adarflag = adarbehave; /* I initialize jul above to stop gcc from complaining about possible use of uninitialized variable. You can take it out if the small inefficiency really bothers you. */ /* If adarbehave == ADAR2BOTH, set adarflag to ADAR2ADARA for now */ if (adarbehave == ADAR2BOTH) adarflag = ADAR2ADARA; JulToHeb(julstart, &yout, &mout, &dout); r = 1; while(r) { r = GetValidHebDate(yout, hm, hd, adarflag, &mout, &dout, jahr); if (dout == -1) return r; if (r) { if (adarbehave == ADAR2BOTH && hm == ADAR) { if (adarflag == ADAR2ADARA) { adarflag = ADAR2ADARB; } else { adarflag = ADAR2ADARA; yout++; } } else yout++; continue; } jul = HebToJul(yout, mout, dout); if (jul < 0) return E_DATE_OVER; if (jul >= julstart) break; else { if (adarbehave == ADAR2BOTH && hm == ADAR) { if (adarflag == ADAR2ADARA) { adarflag = ADAR2ADARB; } else { adarflag = ADAR2ADARA; yout++; } } else yout++; r=1; /* Force loop to continue */ } } *ans = jul; return OK; } /***************************************************************/ /* */ /* ComputeJahr */ /* */ /* Given a date of death, compute the value to use for jahr. */ /* */ /***************************************************************/ int ComputeJahr(int y, int m, int d, int *ans) { char const *monlen; int len; *ans = JAHR_NONE; len = DaysInHebYear(y); monlen = DaysInHebMonths(len); /* Check for Adar A */ if (m == ADARA && monlen[m] == 0) { Eprint("No Adar A in %d", y); return E_BAD_HEBDATE; } if (d < 1 || d > MaxMonLen[m] || m < 0 || m > 13) { return E_BAD_HEBDATE; } if (d > monlen[m]) { Eprint("%d %s %d: %s", d, HebMonthNames[m], y, ErrMsg[E_BAD_HEBDATE]); return E_BAD_HEBDATE; } /* If the jahrzeit was in Adar A, we always use JAHR_BACKWARD */ if (m == ADARA) { *ans = JAHR_BACKWARD; return OK; } /* Get lengths of months in year following jahrzeit */ len = DaysInHebYear(y+1); monlen = DaysInHebMonths(len); if (d > monlen[m]) *ans = JAHR_FORWARD; else *ans = JAHR_BACKWARD; return OK; } remind-03.01.15/src/init.c0000644000076400007640000005370412514120670013246 0ustar dfsdfs/***************************************************************/ /* */ /* INIT.C */ /* */ /* Initialize remind; perform certain tasks between */ /* iterations in calendar mode; do certain checks after end */ /* in normal mode. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2011 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "version.h" #include "config.h" #define L_IN_INIT 1 #include #include #include #include #include #include #include #include "types.h" #include "protos.h" #include "expr.h" #include "err.h" #include "globals.h" /*************************************************************** * * Command line options recognized: * * -n = Output next trigger date of each reminder in * simple calendar format. * -r = Disallow RUN mode * -c[n] = Produce a calendar for n months (default = 1) * -w[n,n,n] = Specify output device width, padding and spacing * -s[n] = Produce calendar in "simple calendar" format * -p[n] = Produce calendar in format compatible with rem2ps * -l = Prefix simple calendar lines with a comment containing * their trigger line numbers and filenames * -v = Verbose mode * -o = Ignore ONCE directives * -a = Don't issue timed reminders which will be queued * -q = Don't queue timed reminders * -t = Trigger all reminders (infinite delta) * -h = Hush mode * -f = Do not fork * -dchars = Debugging mode: Chars are: * f = Trace file openings * e = Echo input lines * x = Display expression evaluation * t = Display trigger dates * v = Dump variables at end * l = Display entire line in error messages * -e = Send messages normally sent to stderr to stdout instead * -z[n] = Daemon mode waking up every n (def 1) minutes. * -bn = Time format for cal (0, 1, or 2) * -xn = Max. number of iterations for SATISFY * -uname = Run as user 'name' - only valid when run by root. If run * by non-root, changes environment but not effective uid. * -kcmd = Run 'cmd' for MSG-type reminders instead of printing to stdout * -iVAR=EXPR = Initialize and preserve VAR. * -m = Start calendar with Monday instead of Sunday. * -j[n] = Purge all junk from reminder files (n = INCLUDE depth) * A minus sign alone indicates to take input from stdin * **************************************************************/ #if defined(__APPLE__) || defined(__CYGWIN__) static void rkrphgvba(int x); #endif /* For parsing an integer */ #define PARSENUM(var, s) \ var = 0; \ while (isdigit(*(s))) { \ var *= 10; \ var += *(s) - '0'; \ s++; \ } static void ChgUser(char const *u); static void InitializeVar(char const *str); static char const *BadDate = "Illegal date on command line\n"; static DynamicBuffer default_filename_buf; /***************************************************************/ /* */ /* DefaultFilename */ /* */ /* If we're invoked as "rem" rather than "remind", use a */ /* default filename. Use $DOTREMINDERS or $HOME/.reminders */ /* */ /***************************************************************/ static char const *DefaultFilename(void) { char const *s; DBufInit(&default_filename_buf); s = getenv("DOTREMINDERS"); if (s) { return s; } s = getenv("HOME"); if (!s) { fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n"); exit(1); } DBufPuts(&default_filename_buf, s); DBufPuts(&default_filename_buf, "/.reminders"); return DBufValue(&default_filename_buf); } /***************************************************************/ /* */ /* InitRemind */ /* */ /* Initialize the system - called only once at beginning! */ /* */ /***************************************************************/ void InitRemind(int argc, char const *argv[]) { char const *arg; int i; int y, m, d, rep; Token tok; int InvokedAsRem = 0; char const *s; int weeks; int jul; #if defined(__APPLE__) rkrphgvba(0); #elif defined(__CYGWIN__) rkrphgvba(1); #endif jul = NO_DATE; /* Initialize global dynamic buffers */ DBufInit(&Banner); DBufInit(&LineBuffer); DBufInit(&ExprBuf); DBufPuts(&Banner, L_BANNER); PurgeFP = NULL; /* Make sure remind is not installed set-uid or set-gid */ if (getgid() != getegid() || getuid() != geteuid()) { fprintf(ErrFp, "\nRemind should not be installed set-uid or set-gid.\nCHECK YOUR SYSTEM SECURITY.\n"); exit(1); } y = NO_YR; m = NO_MON; d = NO_DAY; rep = NO_REP; RealToday = SystemDate(&CurYear, &CurMon, &CurDay); if (RealToday < 0) { fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE); exit(1); } JulianToday = RealToday; FromJulian(JulianToday, &CurYear, &CurMon, &CurDay); /* See if we were invoked as "rem" rather than "remind" */ if (argv[0]) { s = strrchr(argv[0], '/'); if (!s) { s = argv[0]; } else { s++; } if (!strcmp(s, "rem")) { InvokedAsRem = 1; } } /* Parse the command-line options */ i = 1; while (i < argc) { arg = argv[i]; if (*arg != '-') break; /* Exit the loop if it's not an option */ i++; arg++; if (!*arg) { UseStdin = 1; IgnoreOnce = 1; i--; break; } while (*arg) { switch(*arg++) { case 'j': case 'J': PurgeMode = 1; if (*arg) { PARSENUM(PurgeIncludeDepth, arg); } break; case 'i': case 'I': InitializeVar(arg); while(*arg) arg++; break; case 'n': case 'N': NextMode = 1; DontQueue = 1; Daemon = 0; break; case 'r': case 'R': RunDisabled = RUN_CMDLINE; break; case 'm': case 'M': MondayFirst = 1; break; case 'o': case 'O': IgnoreOnce = 1; break; case 'y': case 'Y': SynthesizeTags = 1; break; case 't': case 'T': if (!*arg) { InfiniteDelta = 1; } else { PARSENUM(DeltaOffset, arg); if (DeltaOffset < 0) { DeltaOffset = 0; } } break; case 'e': case 'E': ErrFp = stdout; break; case 'h': case 'H': Hush = 1; break; case 'g': case 'G': SortByDate = SORT_ASCEND; SortByTime = SORT_ASCEND; SortByPrio = SORT_ASCEND; UntimedBeforeTimed = 0; if (*arg) { if (*arg == 'D' || *arg == 'd') SortByDate = SORT_DESCEND; arg++; } if (*arg) { if (*arg == 'D' || *arg == 'd') SortByTime = SORT_DESCEND; arg++; } if (*arg) { if (*arg == 'D' || *arg == 'd') SortByPrio = SORT_DESCEND; arg++; } if (*arg) { if (*arg == 'D' || *arg == 'd') UntimedBeforeTimed = 1; arg++; } break; case 'u': case 'U': ChgUser(arg); RunDisabled = RUN_CMDLINE; while (*arg) arg++; break; case 'z': case 'Z': DontFork = 1; if (*arg == '0') { PARSENUM(Daemon, arg); if (Daemon == 0) Daemon = -1; else if (Daemon < 1) Daemon = 1; else if (Daemon > 60) Daemon = 60; } else { PARSENUM(Daemon, arg); if (Daemon<1) Daemon=1; else if (Daemon>60) Daemon=60; } break; case 'a': case 'A': DontIssueAts++; break; case 'q': case 'Q': DontQueue = 1; break; case 'f': case 'F': DontFork = 1; break; case 'c': case 'C': DoCalendar = 1; weeks = 0; /* Parse the flags */ while(*arg) { if (*arg == 'a' || *arg == 'A') { DoSimpleCalDelta = 1; arg++; continue; } if (*arg == '+') { weeks = 1; arg++; continue; } if (*arg == 'l' || *arg == 'L') { UseVTChars = 1; arg++; continue; } if (*arg == 'u' || *arg == 'U') { UseUTF8Chars = 1; arg++; continue; } if (*arg == 'c' || *arg == 'C') { UseVTColors = 1; arg++; continue; } break; } if (weeks) { PARSENUM(CalWeeks, arg); if (!CalWeeks) CalWeeks = 1; } else { PARSENUM(CalMonths, arg); if (!CalMonths) CalMonths = 1; } break; case 's': case 'S': DoSimpleCalendar = 1; weeks = 0; while(*arg) { if (*arg == 'a' || *arg == 'A') { DoSimpleCalDelta = 1; arg++; continue; } if (*arg == '+') { arg++; weeks = 1; continue; } break; } if (weeks) { PARSENUM(CalWeeks, arg); if (!CalWeeks) CalWeeks = 1; } else { PARSENUM(CalMonths, arg); if (!CalMonths) CalMonths = 1; } break; case 'p': case 'P': DoSimpleCalendar = 1; PsCal = 1; if (*arg == 'a' || *arg == 'A') { DoSimpleCalDelta = 1; arg++; } PARSENUM(CalMonths, arg); if (!CalMonths) CalMonths = 1; break; case 'l': case 'L': DoPrefixLineNo = 1; break; case 'w': case 'W': if (*arg != ',') { PARSENUM(CalWidth, arg); if (CalWidth < 71) CalWidth = 71; } if (*arg == ',') { arg++; if (*arg != ',') { PARSENUM(CalLines, arg); if (CalLines > 20) CalLines = 20; } if (*arg == ',') { arg++; PARSENUM(CalPad, arg); if (CalPad > 20) CalPad = 20; } } break; case 'd': case 'D': while (*arg) { switch(*arg++) { case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break; case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break; case 't': case 'T': DebugFlag |= DB_PRTTRIG; break; case 'v': case 'V': DebugFlag |= DB_DUMP_VARS; break; case 'l': case 'L': DebugFlag |= DB_PRTLINE; break; case 'f': case 'F': DebugFlag |= DB_TRACE_FILES; break; default: fprintf(ErrFp, ErrMsg[M_BAD_DB_FLAG], *(arg-1)); } } break; case 'v': case 'V': DebugFlag |= DB_PRTLINE; ShowAllErrors = 1; break; case 'b': case 'B': PARSENUM(ScFormat, arg); if (ScFormat<0 || ScFormat>2) ScFormat=SC_AMPM; break; case 'x': case 'X': PARSENUM(MaxSatIter, arg); if (MaxSatIter < 10) MaxSatIter=10; break; case 'k': case 'K': MsgCommand = arg; while (*arg) arg++; /* Chew up remaining chars in this arg */ break; default: fprintf(ErrFp, ErrMsg[M_BAD_OPTION], *(arg-1)); } } } /* Get the filename. */ if (!InvokedAsRem) { if (i >= argc) { Usage(); exit(1); } InitialFile = argv[i++]; } else { InitialFile = DefaultFilename(); } /* Get the date, if any */ if (i < argc) { while (i < argc) { arg = argv[i++]; FindToken(arg, &tok); switch (tok.type) { case T_Time: if (SysTime != -1L) Usage(); else { SysTime = (long) tok.val * 60L; DontQueue = 1; Daemon = 0; } break; case T_DateTime: if (SysTime != -1L) Usage(); if (m != NO_MON || d != NO_DAY || y != NO_YR || jul != NO_DATE) Usage(); SysTime = (tok.val % MINUTES_PER_DAY) * 60; DontQueue = 1; Daemon = 0; jul = tok.val / MINUTES_PER_DAY; break; case T_Date: if (m != NO_MON || d != NO_DAY || y != NO_YR || jul != NO_DATE) Usage(); jul = tok.val; break; case T_Month: if (m != NO_MON || jul != NO_DATE) Usage(); else m = tok.val; break; case T_Day: if (d != NO_DAY || jul != NO_DATE) Usage(); else d = tok.val; break; case T_Year: if (y != NO_YR || jul != NO_DATE) Usage(); else y = tok.val; break; case T_Rep: if (rep != NO_REP) Usage(); else rep = tok.val; break; default: Usage(); } } if (rep > 0) { Iterations = rep; DontQueue = 1; Daemon = 0; } if (jul != NO_DATE) { FromJulian(jul, &y, &m, &d); } /* Must supply date in the form: day, mon, yr OR mon, yr */ if (m != NO_MON || y != NO_YR || d != NO_DAY) { if (m == NO_MON || y == NO_YR) { if (rep == NO_REP) Usage(); else if (m != NO_MON || y != NO_YR) Usage(); else { m = CurMon; y = CurYear; if (d == NO_DAY) d = CurDay; } } if (d == NO_DAY) d=1; if (d > DaysInMonth(m, y)) { fprintf(ErrFp, "%s", BadDate); Usage(); } JulianToday = Julian(y, m, d); if (JulianToday == -1) { fprintf(ErrFp, "%s", BadDate); Usage(); } CurYear = y; CurMon = m; CurDay = d; if (JulianToday != RealToday) IgnoreOnce = 1; } } /* Figure out the offset from UTC */ if (CalculateUTC) (void) CalcMinsFromUTC(JulianToday, SystemTime(1)/60, &MinsFromUTC, NULL); } /***************************************************************/ /* */ /* Usage */ /* */ /* Print the usage info. */ /* */ /***************************************************************/ #ifndef L_USAGE_OVERRIDE void Usage(void) { fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1998 Dianne Skoll\n", VERSION, L_LANGNAME); fprintf(ErrFp, "Copyright 1999-2011 Roaring Penguin Software Inc.\n"); #ifdef BETA fprintf(ErrFp, ">>>> BETA VERSION <<<<\n"); #endif fprintf(ErrFp, "Usage: remind [options] filename [date] [time] [*rep]\n"); fprintf(ErrFp, "Options:\n"); fprintf(ErrFp, " -n Output next occurrence of reminders in simple format\n"); fprintf(ErrFp, " -r Disable RUN directives\n"); fprintf(ErrFp, " -c[a][n] Produce a calendar for n (default 1) months\n"); fprintf(ErrFp, " -c[a]+[n] Produce a calendar for n (default 1) weeks\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Specify width, padding and spacing of calendar\n"); fprintf(ErrFp, " -s[a][+][n] Produce `simple calendar' for n (1) months (weeks)\n"); fprintf(ErrFp, " -p[a][n] Same as -s, but input compatible with rem2ps\n"); fprintf(ErrFp, " -l Prefix each simple calendar line with line number and filename comment\n"); fprintf(ErrFp, " -v Verbose mode\n"); fprintf(ErrFp, " -o Ignore ONCE directives\n"); fprintf(ErrFp, " -t[n] Trigger all future (or those within `n' days)\n"); fprintf(ErrFp, " -h `Hush' mode - be very quiet\n"); fprintf(ErrFp, " -a Don't trigger timed reminders immediately - just queue them\n"); fprintf(ErrFp, " -q Don't queue timed reminders\n"); fprintf(ErrFp, " -f Trigger timed reminders by staying in foreground\n"); fprintf(ErrFp, " -z[n] Enter daemon mode, waking every n (1) minutes.\n"); fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline f=tracefiles\n"); fprintf(ErrFp, " -e Divert messages normally sent to stderr to stdout\n"); fprintf(ErrFp, " -b[n] Time format for cal: 0=am/pm, 1=24hr, 2=none\n"); fprintf(ErrFp, " -x[n] Iteration limit for SATISFY clause (def=150)\n"); fprintf(ErrFp, " -kcmd Run `cmd' for MSG-type reminders\n"); fprintf(ErrFp, " -g[dddd] Sort reminders by date, time, priority, and 'timedness'\n"); fprintf(ErrFp, " -ivar=val Initialize var to val and preserve var\n"); fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n"); fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n"); fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n"); exit(1); } #endif /* L_USAGE_OVERRIDE */ /***************************************************************/ /* */ /* ChgUser */ /* */ /* Run as a specified user. Can only be used if Remind is */ /* started by root. This changes the real and effective uid, */ /* the real and effective gid, and sets the HOME, SHELL and */ /* USER environment variables. */ /* */ /***************************************************************/ static void ChgUser(char const *user) { uid_t myuid; struct passwd *pwent; static char *home; static char *shell; static char *username; static char *logname; myuid = getuid(); pwent = getpwnam(user); if (!pwent) { fprintf(ErrFp, ErrMsg[M_BAD_USER], user); exit(1); } if (!myuid && setgid(pwent->pw_gid)) { fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid); exit(1); } if (!myuid && setuid(pwent->pw_uid)) { fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid); exit(1); } home = malloc(strlen(pwent->pw_dir) + 6); if (!home) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); exit(1); } sprintf(home, "HOME=%s", pwent->pw_dir); putenv(home); shell = malloc(strlen(pwent->pw_shell) + 7); if (!shell) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); exit(1); } sprintf(shell, "SHELL=%s", pwent->pw_shell); putenv(shell); if (pwent->pw_uid) { username = malloc(strlen(pwent->pw_name) + 6); if (!username) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); exit(1); } sprintf(username, "USER=%s", pwent->pw_name); putenv(username); logname= malloc(strlen(pwent->pw_name) + 9); if (!logname) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); exit(1); } sprintf(logname, "LOGNAME=%s", pwent->pw_name); putenv(logname); } } static void DefineFunction(char const *str) { Parser p; int r; CreateParser(str, &p); r = DoFset(&p); DestroyParser(&p); if (r != OK) { fprintf(ErrFp, "-i option: %s: %s\n", str, ErrMsg[r]); } } /***************************************************************/ /* */ /* InitializeVar */ /* */ /* Initialize and preserve a variable */ /* */ /***************************************************************/ static void InitializeVar(char const *str) { char const *expr; char const *ostr = str; char varname[VAR_NAME_LEN+1]; Value val; int r; /* Scan for an '=' sign */ r = 0; while (*str && *str != '=') { if (r < VAR_NAME_LEN) { varname[r++] = *str; } if (*str == '(') { /* Do a function definition if we see a paren */ DefineFunction(ostr); return; } str++; } varname[r] = 0; if (!*str) { fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EQ]); return; } if (!*varname) { fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_VAR]); return; } expr = str+1; if (!*expr) { fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EXPR]); return; } r=EvalExpr(&expr, &val, NULL); if (r) { fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]); return; } if (*varname == '$') { r=SetSysVar(varname+1, &val); if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]); return; } r=SetVar(varname, &val); if (r) { fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]); return; } r=PreserveVar(varname); if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]); return; } #if defined(__APPLE__) || defined(__CYGWIN__) static char const pmsg1[] = { 0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20, 0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76, 0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62, 0x61, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x63, 0x63, 0x79, 0x72, 0x20, 0x63, 0x65, 0x62, 0x71, 0x68, 0x70, 0x67, 0x2e, 0x20, 0x20, 0x56, 0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65, 0x20, 0x67, 0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71, 0x76, 0x71, 0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76, 0x62, 0x61, 0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61, 0x67, 0x76, 0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61, 0x67, 0x6e, 0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00 }; static char const pmsg2[] = { 0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20, 0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76, 0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62, 0x61, 0x20, 0x6e, 0x20, 0x5a, 0x76, 0x70, 0x65, 0x62, 0x66, 0x62, 0x73, 0x67, 0x20, 0x66, 0x6c, 0x66, 0x67, 0x72, 0x7a, 0x2e, 0x20, 0x20, 0x56, 0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65, 0x20, 0x67, 0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71, 0x76, 0x71, 0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76, 0x62, 0x61, 0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61, 0x67, 0x76, 0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61, 0x67, 0x6e, 0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00 }; static void rkrphgvba(int x) { char const *s = (x ? pmsg2 : pmsg1); while(*s) { int c = (int) *s++; c=isalpha(c)?tolower(c)<0x6e?c+13:c-13:c; putchar(c); } sleep(5); } #endif remind-03.01.15/src/lang.h0000644000076400007640000000660312514120665013231 0ustar dfsdfs/***************************************************************/ /* */ /* LANG.H */ /* */ /* Header file for language support for various languages. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* I'm chauvinistic and name each language with its English name... */ #define ENGLISH 0 /* original by Dianne Skoll */ #define GERMAN 1 /* translated by Wolfgang Thronicke */ #define DUTCH 2 /* translated by Willem Kasdorp and Erik-Jan Vens */ #define FINNISH 3 /* translated by Mikko Silvonen */ #define FRENCH 4 /* translated by Laurent Duperval */ #define NORWEGIAN 5 /* translated by Trygve Randen */ #define DANISH 6 /* translated by Mogens Lynnerup */ #define POLISH 7 /* translated by Jerzy Sobczyk */ #define BRAZPORT 8 /* Brazilian Portuguese by Marco Paganini */ #define ITALIAN 9 /* translated by Valerio Aimale */ #define ROMANIAN 10 /* translated by Liviu Daia */ #define SPANISH 11 /* translated by Rafa Couto */ #define ICELANDIC 12 /* translated by Bjrn Davsson */ /* Add more languages here - but please e-mail dfs@roaringpenguin.com to have your favorite language assigned a number. If you add a language, please send me the header file, and permission to include it in future releases of Remind. Note that you'll get no remuneration for this service - just everlasting fame. :-) Use the file tstlang.rem to test your new language file. */ /************************************************************************ * * * Define the language you want to use here * * * ************************************************************************/ #ifndef LANG /* Allow for definition on compiler command line */ #define LANG ENGLISH #endif /* Pick up the appropriate header file */ #if LANG == ENGLISH #include "langs/english.h" #elif LANG == GERMAN #include "langs/german.h" #elif LANG == DUTCH #include "langs/dutch.h" #elif LANG == FINNISH #include "langs/finnish.h" #elif LANG == FRENCH #include "langs/french.h" #elif LANG == NORWEGIAN #include "langs/norwgian.h" #elif LANG == DANISH #include "langs/danish.h" #elif LANG == POLISH #include "langs/polish.h" #elif LANG == BRAZPORT #include "langs/portbr.h" #elif LANG == ITALIAN #include "langs/italian.h" #elif LANG == ROMANIAN #include "langs/romanian.h" #elif LANG == SPANISH #include "langs/spanish.h" #elif LANG == ICELANDIC #include "langs/icelandic.h" /* If no sensible language, choose English. I intended to use the #error directive here, but some C compilers barf. */ #else #include "langs/english.h" #endif remind-03.01.15/src/langs/danish.h0000644000076400007640000000732512514120660014657 0ustar dfsdfs/***************************************************************/ /* */ /* DANISH.H */ /* */ /* Support for the Danish language. */ /* */ /* This file is part of REMIND. */ /* */ /* REMIND is Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* This file is Copyright (C) 1993 by Mogens Lynnerup. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Danish" /* Day names */ #if ISOLATIN1 # define L_SUNDAY "S\370ndag" #else # define L_SUNDAY "Soendag" #endif #define L_MONDAY "Mandag" #define L_TUESDAY "Tirsdag" #define L_WEDNESDAY "Onsdag" #define L_THURSDAY "Torsdag" #define L_FRIDAY "Fredag" #if ISOLATIN1 # define L_SATURDAY "L\370rdag" #else # define L_SATURDAY "Loerdag" #endif /* Month names */ #define L_JAN "Januar" #define L_FEB "Februar" #define L_MAR "Marts" #define L_APR "April" #define L_MAY "Maj" #define L_JUN "Juni" #define L_JUL "Juli" #define L_AUG "August" #define L_SEP "September" #define L_OCT "Oktober" #define L_NOV "November" #define L_DEC "December" /* Today and tomorrow */ #define L_TODAY "i dag" #define L_TOMORROW "i morgen" /* The default banner */ #if ISOLATIN1 # define L_BANNER "P\345mindelse for %w, %d. %m, %y%o:" #else # define L_BANNER "Paamindelse for %w, %d. %m, %y%o:" #endif /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "siden" #define L_FROMNOW "fra nu" /* "in %d days' time" */ #define L_INXDAYS "om %d dage" /* "on" as in "on date..." */ #if ISOLATIN1 # define L_ON "p\345" #else # define L_ON "paa" #endif /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "e" /* Minutes, hours, at, etc */ #define L_NOW "nu" #define L_AT "kl." #define L_MINUTE "minut" #define L_HOUR "time" #define L_IS "er" #define L_WAS "var" #define L_AND "og" /* What to add to make "hour" plural */ #define L_HPLU "r" /* What to add to make "minute" plural */ #define L_MPLU "ter" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<5) ? " om natten" : " om formiddagen" : (hour > 17) ? " om aftenen" : " om eftermiddagen"; #define L_ORDINAL_OVERRIDE plu = "."; #define L_A_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, den %d. %s %d", L_ON, DayName[jul%7], d, MonthName[m], y); } #define L_E_OVER sprintf(s, "den %02d%c%02d%c%04d", d, DateSep, m+1, DateSep, y); #define L_F_OVER sprintf(s, "den %02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y); #define L_G_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s", DayName[jul%7], d, MonthName[m]); } else { sprintf(s, "%s %s, den %d. %s", L_ON, DayName[jul%7], d, MonthName[m]); } #define L_H_OVER sprintf(s, "den %02d%c%02d", d, DateSep, m+1); #define L_I_OVER sprintf(s, "den %02d%c%02d", m+1, DateSep, d); #define L_U_OVER L_A_OVER #define L_V_OVER L_G_OVER #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/dutch.h0000644000076400007640000000643212514120651014516 0ustar dfsdfs/***************************************************************/ /* */ /* DUTCH.H */ /* */ /* Support for the DUTCH language. */ /* */ /* Author: Willem Kasdorp */ /* */ /* Modified slightly by Dianne Skoll */ /* */ /* Further corrections by Erik-Jan Vens */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Dutch" /* Day names */ #define L_SUNDAY "zondag" #define L_MONDAY "maandag" #define L_TUESDAY "dinsdag" #define L_WEDNESDAY "woensdag" #define L_THURSDAY "donderdag" #define L_FRIDAY "vrijdag" #define L_SATURDAY "zaterdag" /* Month names */ #define L_JAN "januari" #define L_FEB "februari" #define L_MAR "maart" #define L_APR "april" #define L_MAY "mei" #define L_JUN "juni" #define L_JUL "juli" #define L_AUG "augustus" #define L_SEP "september" #define L_OCT "oktober" #define L_NOV "november" #define L_DEC "december" /* Today and tomorrow */ #define L_TODAY "vandaag" #define L_TOMORROW "morgen" /* The default banner */ #define L_BANNER "Herinneringen voor %w, %d%s %m, %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "geleden" #define L_FROMNOW "vanaf nu" /* "in %d days' time" */ #define L_INXDAYS "over %d dagen" /* "on" as in "on date..." */ #define L_ON "op" /* Pluralizing - this is a problem for many languages and may require a more drastic fix. (Indeed..., wkasdo) */ #define L_PLURAL "s" /* Minutes, hours, at, etc */ #define L_NOW "nu" #define L_AT "op" #define L_MINUTE "minuut" #define L_HOUR "uur" #define L_IS "is" #define L_WAS "was" #define L_AND "en" /* What to add to make "hour" plural (should result in uren, not uuren (wkasdo) */ #define L_HPLU "en" /* What to add to make "minute" plural (should be minuten, not minuuten) */ #define L_MPLU "en" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ /* Willem - I fixed the uren/uuren problem here */ #define L_1_OVER \ if (tdiff == 0) \ sprintf(s, L_NOW); \ else if (hdiff == 0) \ sprintf(s, "%d %s %s", mdiff, \ (mdiff == 1 ? "minuut" : "minuten"), when); \ else if (mdiff == 0) \ sprintf(s, "%d %s %s", hdiff, \ (mdiff == 1 ? "uur" : "uren"), when); \ else sprintf(s, "%d %s %s %d %s %s", hdiff, \ (hdiff == 1 ? "uur" : "uren"), \ L_AND, mdiff, \ (mdiff == 1 ? "minuut" : "minuten"), \ when); #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/english.h0000644000076400007640000000450612514120642015040 0ustar dfsdfs/***************************************************************/ /* */ /* ENGLISH.H */ /* */ /* Support for the English language. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "English" /* Day names */ #define L_SUNDAY "Sunday" #define L_MONDAY "Monday" #define L_TUESDAY "Tuesday" #define L_WEDNESDAY "Wednesday" #define L_THURSDAY "Thursday" #define L_FRIDAY "Friday" #define L_SATURDAY "Saturday" /* Month names */ #define L_JAN "January" #define L_FEB "February" #define L_MAR "March" #define L_APR "April" #define L_MAY "May" #define L_JUN "June" #define L_JUL "July" #define L_AUG "August" #define L_SEP "September" #define L_OCT "October" #define L_NOV "November" #define L_DEC "December" /* Today and tomorrow */ #define L_TODAY "today" #define L_TOMORROW "tomorrow" /* The default banner */ #define L_BANNER "Reminders for %w, %d%s %m, %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "ago" #define L_FROMNOW "from now" /* "in %d days' time" */ #define L_INXDAYS "in %d days' time" /* "on" as in "on date..." */ #define L_ON "on" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "s" /* Minutes, hours, at, etc */ #define L_NOW "now" #define L_AT "at" #define L_MINUTE "minute" #define L_HOUR "hour" #define L_IS "is" #define L_WAS "was" #define L_AND "and" /* What to add to make "hour" plural */ #define L_HPLU "s" /* What to add to make "minute" plural */ #define L_MPLU "s" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/finnish.h0000644000076400007640000006105112531375606015056 0ustar dfsdfs/***************************************************************/ /* */ /* FINNISH.H */ /* */ /* Support for the Finnish language. */ /* */ /* Author: Mikko Silvonen */ /* */ /* See http://www.iki.fi/silvonen/remind/ for a list of */ /* Finnish holidays. */ /* */ /* This file is part of REMIND. */ /* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */ /* REMIND is Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Finnish" /* Day names */ #define L_SUNDAY "sunnuntai" #define L_MONDAY "maanantai" #define L_TUESDAY "tiistai" #define L_WEDNESDAY "keskiviikko" #define L_THURSDAY "torstai" #define L_FRIDAY "perjantai" #define L_SATURDAY "lauantai" /* Month names */ #define L_JAN "tammikuu" #define L_FEB "helmikuu" #define L_MAR "maaliskuu" #define L_APR "huhtikuu" #define L_MAY "toukokuu" #if ISOLATIN1 #define L_JUN "kes\xE4kuu" #define L_JUL "hein\xE4kuu" #elif IBMEXTENDED #define L_JUN "kes\x84kuu" #define L_JUL "hein\x84kuu" #else #define L_JUN "kes{kuu" #define L_JUL "hein{kuu" #endif #define L_AUG "elokuu" #define L_SEP "syyskuu" #define L_OCT "lokakuu" #define L_NOV "marraskuu" #define L_DEC "joulukuu" /* Today and tomorrow */ #if ISOLATIN1 #define L_TODAY "t\xE4n\xE4\xE4n" #elif IBMEXTENDED #define L_TODAY "t\x84n\x84\x84n" #else #define L_TODAY "t{n{{n" #endif #define L_TOMORROW "huomenna" /* The default banner */ #define L_BANNER "Viestit %wna %d. %mta %y%o:" /* "am" and "pm" */ #define L_AM " ap." #define L_PM " ip." /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "sitten" #define L_FROMNOW "kuluttua" /* "in %d days' time" */ #if ISOLATIN1 #define L_INXDAYS "%d p\xE4iv\xE4n kuluttua" #elif IBMEXTENDED #define L_INXDAYS "%d p\x84iv\x84n kuluttua" #else #define L_INXDAYS "%d p{iv{n kuluttua" #endif /* "on" as in "on date...", but in Finnish it is a case ending; L_PARTIT is the partitive ending appended to -kuu and -tai */ #define L_ON "na" #define L_PARTIT "ta" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ /* The partitive ending of "day" */ #if ISOLATIN1 #define L_PLURAL "\xE4" #elif IBMEXTENDED #define L_PLURAL "\x84" #else #define L_PLURAL "{" #endif /* Minutes, hours, at, etc */ #define L_NOW "nyt" #define L_AT "klo" #define L_MINUTE "minuutti" #define L_HOUR "tunti" #define L_IS "on" #define L_WAS "oli" #define L_AND "ja" /* What to add to make "hour" plural (or actually partitive) */ #define L_HPLU "a" /* What to add to make "minute" plural (or actually partitive) */ #define L_MPLU "a" /* Genitive form of "hour" */ #define L_HGEN "tunnin" /* Genitive form of "minute" */ #define L_MGEN "minuutin" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #if ISOLATIN1 #define L_ORDINAL_OVERRIDE switch(d) { \ case 1: plu = ":sen\xE4"; break; \ case 2: plu = ":sena"; break; \ default: \ switch(d%10) { \ case 2: \ case 3: \ case 6: \ case 8: plu = ":ntena"; break; \ default: plu = ":nten\xE4"; break; \ } \ } #elif IBMEXTENDED #define L_ORDINAL_OVERRIDE switch(d) { \ case 1: plu = ":sen\x84"; break; \ case 2: plu = ":sena"; break; \ default: \ switch(d%10) { \ case 2: \ case 3: \ case 6: \ case 8: plu = ":ntena"; break; \ default: plu = ":nten\x84"; break; \ } \ } #else #define L_ORDINAL_OVERRIDE switch(d) { \ case 1: plu = ":sen{"; break; \ case 2: plu = ":sena"; break; \ default: \ switch(d%10) { \ case 2: \ case 3: \ case 6: \ case 8: plu = ":ntena"; break; \ default: plu = ":nten{"; break; \ } \ } #endif #define L_A_OVER if (altmode == '*') { sprintf(s, "%s %d. %s %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s%s %d. %s%s %d", DayName[jul%7], L_ON, d, MonthName[m], L_PARTIT, y); } #define L_C_OVER if (altmode == '*') { sprintf(s, "%s", DayName[jul%7]); } else { sprintf(s, "%s%s", DayName[jul%7], L_ON); } #define L_E_OVER sprintf(s, "%02d%c%02d%c%04d", d, DateSep, m+1, DateSep, y); #define L_F_OVER sprintf(s, "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y); #define L_G_OVER if (altmode == '*') { sprintf(s, "%s %d. %s", DayName[jul%7], d, MonthName[m]); } else { sprintf(s, "%s%s %d. %s%s", DayName[jul%7], L_ON, d, MonthName[m], L_PARTIT); } #define L_H_OVER sprintf(s, "%02d%c%02d", d, DateSep, m+1); #define L_I_OVER sprintf(s, "%02d%c%02d", m+1, DateSep, d); #define L_J_OVER if (altmode == '*') { sprintf(s, "%s %sn %d%s %d", DayName[jul%7], MonthName[m], d, plu, y); } else { sprintf(s, "%s%s %sn %d%s %d", DayName[jul%7], L_ON, MonthName[m], d, plu, y); } #define L_K_OVER if (altmode == '*') { sprintf(s, "%s %sn %d%s", DayName[jul%7], MonthName[m], d, plu); } else { sprintf(s, "%s%s %sn %d%s", DayName[jul%7], L_ON, MonthName[m], d, plu); } #define L_L_OVER sprintf(s, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d); #define L_Q_OVER sprintf(s, "n"); #define L_U_OVER if (altmode == '*') { sprintf(s, "%s %d%s %s %d", DayName[jul%7], d, plu, MonthName[m], y); } else { sprintf(s, "%s%s %d%s %s%s %d", DayName[jul%7], L_ON, d, plu, MonthName[m], L_PARTIT, y); } #define L_V_OVER if (altmode == '*') { sprintf(s, "%s %d%s %s", DayName[jul%7], d, plu, MonthName[m]); } else { sprintf(s, "%s%s %d%s %s%s", DayName[jul%7], L_ON, d, plu, MonthName[m], L_PARTIT); } #define L_1_OVER \ if (tdiff == 0) \ sprintf(s, "%s", L_NOW); \ else { \ s[0] = '\0'; \ if (hdiff != 0) { \ if (tdiff < 0) \ sprintf(s, "%d %s%s ", hdiff, L_HOUR, hplu); \ else \ sprintf(s, "%d %s ", hdiff, L_HGEN); \ } \ if (mdiff != 0) { \ if (tdiff < 0) \ sprintf(s + strlen(s), "%d %s%s ", mdiff, L_MINUTE, mplu); \ else \ sprintf(s + strlen(s), "%d %s ", mdiff, L_MGEN); \ } \ sprintf(s + strlen(s), when); \ } #endif /* L_IN_DOSUBST */ /* The next ones are used only when MK_GLOBALS is set */ #ifdef MK_GLOBALS #define L_ERR_OVERRIDE 1 EXTERN char *ErrMsg[] = { #if ISOLATIN1 "Ok", "Puuttuva ']'", "Puuttuva lainausmerkki", "Liian monimutkainen lauseke - liikaa operaattoreita", "Liian monimutkainen lauseke - liikaa operandeja", "Puuttuva ')'", "M\xE4\xE4rittelem\xE4t\xF6n funktio", "Virheellinen merkki", "Kaksipaikkainen operaattori puuttuu", "Muisti loppui", "Virheellinen luku", "Operaattoripino tyhj\xE4 - sis\xE4inen virhe", "Muuttujapino tyhj\xE4 - sis\xE4inen virhe", "Tyyppimuunnos ei onnistu", "Virheellinen tyyppi", "Liian suuri p\xE4iv\xE4ys", "Pinovirhe - sis\xE4inen virhe", "Jako nollalla", "M\xE4\xE4rittelem\xE4t\xF6n funktio", "Odottamaton rivin loppu", "Odottamaton tiedoston loppu", "Sy\xF6tt\xF6- tai tulostusvirhe", "Liian pitk\xE4 rivi", "Sis\xE4inen virhe", "Virheellinen p\xE4iv\xE4ys", "Liian v\xE4h\xE4n argumentteja", "Liian paljon argumentteja", "Virheellinen aika", "Liian suuri luku", "Liian pieni luku", "Tiedoston avaus ei onnistu", "Liian monta sis\xE4kk\xE4ist\xE4 INCLUDEa", "J\xE4sennysvirhe", "Laukaisuhetken laskenta ei onnistu", "Liian monta sis\xE4kk\xE4ist\xE4 IF-lausetta", "ELSE ilman IF-lausetta", "ENDIF ilman IF-lausetta", "Kaikkia viikonp\xE4ivi\xE4 ei voi j\xE4tt\xE4\xE4 pois", "Ylim\xE4\xE4r\xE4isi\xE4 merkkej\xE4 rivill\xE4", "POP-OMIT-CONTEXT ilman PUSH-OMIT-CONTEXTia", "RUN-lauseen k\xE4ytt\xF6 estetty", "Arvoaluevirhe", "Virheellinen tunniste", "Rekursiivinen funktiokutsu havaittu", "", "J\xE4rjestelm\xE4muuttujan muuttaminen ei onnistu", "C-kirjastofunktio ei pysty esitt\xE4m\xE4\xE4n p\xE4iv\xE4yst\xE4 tai aikaa", "Sis\xE4isen funktion m\xE4\xE4ritelm\xE4\xE4 yritettiin muuttaa", "Lausekkeessa ei voi olla sis\xE4kk\xE4isi\xE4 funktiom\xE4\xE4ritelmi\xE4", "P\xE4iv\xE4yksen t\xE4ytyy olla t\xE4ydellinen toistokertoimessa", "Vuosi annettu kahdesti", "Kuukausi annettu kahdesti", "P\xE4iv\xE4 annettu kahdesti", "Tuntematon sana tai merkki", "OMIT-komennossa on annettava kuukausi ja p\xE4iv\xE4", "Liian monta osittaista OMIT-komentoa", "Liian monta t\xE4ydellist\xE4 OMIT-komentoa", "Varoitus: PUSH-OMIT-CONTEXT ilman POP-OMIT-CONTEXTia", "Virhe tiedoston luvussa", "Pilkku puuttuu", "Virheellinen juutalainen p\xE4iv\xE4ys", "IIF vaatii parittoman m\xE4\xE4r\xE4n argumentteja", "Varoitus: puuttuva ENDIF", "Pilkku puuttuu", "Viikonp\xE4iv\xE4 annettu kahdesti", "K\xE4yt\xE4 vain yht\xE4 komennoista BEFORE, AFTER ja SKIP", "Sis\xE4kk\xE4isi\xE4 MSG-, MSF- ja RUN-lauseita ei voi k\xE4ytt\xE4\xE4 lausekkeessa", "Toistokerroin annettu kahdesti", "Delta-arvo annettu kahdesti", "Peruutusarvo annettu kahdesti", "ONCE-avainsanaa k\xE4ytetty kahdesti. (Hah.)", "AT-sanan per\xE4st\xE4 puuttuu aika", "THROUGH/UNTIL-sanaa k\xE4ytetty kahdesti", "Ep\xE4t\xE4ydellinen p\xE4iv\xE4ys", "FROM/SCANFROM-sanaa k\xE4ytetty kahdesti", "Muuttuja", "Arvo", "*M\xC4\xC4RITTELEM\xC4T\xD6N*", "Siirryt\xE4\xE4n funktioon", "Poistutaan funktiosta", "Vanhentunut", "fork() ep\xE4onnistui - jonomuistutukset eiv\xE4t toimi", "Tiedoston avaus ei onnistu", "Virheellinen j\xE4rjestelm\xE4p\xE4iv\xE4ys: vuosi on v\xE4hemm\xE4n kuin %d\n", "Tuntematon virheenetsint\xE4tarkenne '%c'\n", "Tuntematon tarkenne '%c'\n", "Tuntematon k\xE4ytt\xE4j\xE4 '%s'\n", "Ryhm\xE4numeron vaihto %d:ksi ei onnistunut\n", "K\xE4ytt\xE4j\xE4numeron vaihto %d:ksi ei onnistunut\n", "Muisti ei riit\xE4 ymp\xE4rist\xF6lle\n", "Puuttuva '='-merkki", "Puuttuva muuttujanimi", "Puuttuva lauseke", "P\xE4iv\xE4n asetus %s:ksi ei onnitus\n", "Remind: tarkenne '-i': %s\n", "Ei viestej\xE4.", "%d viesti(\xE4) t\xE4m\xE4n p\xE4iv\xE4n jonossa.\n", "Numero puuttuu", "Virheellinen funktio WARN-lausekkeessa", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" #elif IBMEXTENDED "Ok", "Puuttuva ']'", "Puuttuva lainausmerkki", "Liian monimutkainen lauseke - liikaa operaattoreita", "Liian monimutkainen lauseke - liikaa operandeja", "Puuttuva ')'", "M\x84\x84rittelem\x84t\x94n funktio", "Virheellinen merkki", "Kaksipaikkainen operaattori puuttuu", "Muisti loppui", "Virheellinen luku", "Operaattoripino tyhj\x84 - sis\x84inen virhe", "Muuttujapino tyhj\x84 - sis\x84inen virhe", "Tyyppimuunnos ei onnistu", "Virheellinen tyyppi", "Liian suuri p\x84iv\x84ys", "Pinovirhe - sis\x84inen virhe", "Jako nollalla", "M\x84\x84rittelem\x84t\x94n funktio", "Odottamaton rivin loppu", "Odottamaton tiedoston loppu", "Sy\x94tt\x94- tai tulostusvirhe", "Liian pitk\x84 rivi", "Sis\x84inen virhe", "Virheellinen p\x84iv\x84ys", "Liian v\x84h\x84n argumentteja", "Liian paljon argumentteja", "Virheellinen aika", "Liian suuri luku", "Liian pieni luku", "Tiedoston avaus ei onnistu", "Liian monta sis\x84kk\x84ist\x84 INCLUDEa", "J\x84sennysvirhe", "Laukaisuhetken laskenta ei onnistu", "Liian monta sis\x84kk\x84ist\x84 IF-lausetta", "ELSE ilman IF-lausetta", "ENDIF ilman IF-lausetta", "Kaikkia viikonp\x84ivi\x84 ei voi j\x84tt\x84\x84 pois", "Ylim\x84\x84r\x84isi\x84 merkkej\x84 rivill\x84", "POP-OMIT-CONTEXT ilman PUSH-OMIT-CONTEXTia", "RUN-lauseen k\x84ytt\x94 estetty", "Arvoaluevirhe", "Virheellinen tunniste", "Rekursiivinen funktiokutsu havaittu", "", "J\x84rjestelm\x84muuttujan muuttaminen ei onnistu", "C-kirjastofunktio ei pysty esitt\x84m\x84\x84n p\x84iv\x84yst\x84 tai aikaa", "Sis\x84isen funktion m\x84\x84ritelm\x84\x84 yritettiin muuttaa", "Lausekkeessa ei voi olla sis\x84kk\x84isi\x84 funktiom\x84\x84ritelmi\x84", "P\x84iv\x84yksen t\x84ytyy olla t\x84ydellinen toistokertoimessa", "Vuosi annettu kahdesti", "Kuukausi annettu kahdesti", "P\x84iv\x84 annettu kahdesti", "Tuntematon sana tai merkki", "OMIT-komennossa on annettava kuukausi ja p\x84iv\x84", "Liian monta osittaista OMIT-komentoa", "Liian monta t\x84ydellist\x84 OMIT-komentoa", "Varoitus: PUSH-OMIT-CONTEXT ilman POP-OMIT-CONTEXTia", "Virhe tiedoston luvussa", "Pilkku puuttuu", "Virheellinen juutalainen p\x84iv\x84ys", "IIF vaatii parittoman m\x84\x84r\x84n argumentteja", "Varoitus: puuttuva ENDIF", "Pilkku puuttuu", "Viikonp\x84iv\x84 annettu kahdesti", "K\x84yt\x84 vain yht\x84 komennoista BEFORE, AFTER ja SKIP", "Sis\x84kk\x84isi\x84 MSG-, MSF- ja RUN-lauseita ei voi k\x84ytt\x84\x84 lausekkeessa", "Toistokerroin annettu kahdesti", "Delta-arvo annettu kahdesti", "Peruutusarvo annettu kahdesti", "ONCE-avainsanaa k\x84ytetty kahdesti. (Hah.)", "AT-sanan per\x84st\x84 puuttuu aika", "THROUGH/UNTIL-sanaa k\x84ytetty kahdesti", "Ep\x84t\x84ydellinen p\x84iv\x84ys", "FROM/SCANFROM-sanaa k\x84ytetty kahdesti", "Muuttuja", "Arvo", "*M\x8E\x8ERITTELEM\x8ET\x99N*", "Siirryt\x84\x84n funktioon", "Poistutaan funktiosta", "Vanhentunut", "fork() ep\x84onnistui - jonomuistutukset eiv\x84t toimi", "Tiedoston avaus ei onnistu", "Virheellinen j\x84rjestelm\x84p\x84iv\x84ys: vuosi on v\x84hemm\x84n kuin %d\n", "Tuntematon virheenetsint\x84tarkenne '%c'\n", "Tuntematon tarkenne '%c'\n", "Tuntematon k\x84ytt\x84j\x84 '%s'\n", "Ryhm\x84numeron vaihto %d:ksi ei onnistunut\n", "K\x84ytt\x84j\x84numeron vaihto %d:ksi ei onnistunut\n", "Muisti ei riit\x84 ymp\x84rist\x94lle\n", "Puuttuva '='-merkki", "Puuttuva muuttujanimi", "Puuttuva lauseke", "P\x84iv\x84n asetus %s:ksi ei onnitus\n", "Remind: tarkenne '-i': %s\n", "Ei viestej\x84.", "%d viesti(\x84) t\x84m\x84n p\x84iv\x84n jonossa.\n", "Numero puuttuu" "Virheellinen funktio WARN-lausekkeessa", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" #else "Ok", "Puuttuva ']'", "Puuttuva lainausmerkki", "Liian monimutkainen lauseke - liikaa operaattoreita", "Liian monimutkainen lauseke - liikaa operandeja", "Puuttuva ')'", "M{{rittelem{t|n funktio", "Virheellinen merkki", "Kaksipaikkainen operaattori puuttuu", "Muisti loppui", "Virheellinen luku", "Operaattoripino tyhj{ - sis{inen virhe", "Muuttujapino tyhj{ - sis{inen virhe", "Tyyppimuunnos ei onnistu", "Virheellinen tyyppi", "Liian suuri p{iv{ys", "Pinovirhe - sis{inen virhe", "Jako nollalla", "M{{rittelem{t|n funktio", "Odottamaton rivin loppu", "Odottamaton tiedoston loppu", "Sy|tt|- tai tulostusvirhe", "Liian pitk{ rivi", "Sis{inen virhe", "Virheellinen p{iv{ys", "Liian v{h{n argumentteja", "Liian paljon argumentteja", "Virheellinen aika", "Liian suuri luku", "Liian pieni luku", "Tiedoston avaus ei onnistu", "Liian monta sis{kk{ist{ INCLUDEa", "J{sennysvirhe", "Laukaisuhetken laskenta ei onnistu", "Liian monta sis{kk{ist{ IF-lausetta", "ELSE ilman IF-lausetta", "ENDIF ilman IF-lausetta", "Kaikkia viikonp{ivi{ ei voi j{tt{{ pois", "Ylim{{r{isi{ merkkej{ rivill{", "POP-OMIT-CONTEXT ilman PUSH-OMIT-CONTEXTia", "RUN-lauseen k{ytt| estetty", "Arvoaluevirhe", "Virheellinen tunniste", "Rekursiivinen funktiokutsu havaittu", "", "J{rjestelm{muuttujan muuttaminen ei onnistu", "C-kirjastofunktio ei pysty esitt{m{{n p{iv{yst{ tai aikaa", "Sis{isen funktion m{{ritelm{{ yritettiin muuttaa", "Lausekkeessa ei voi olla sis{kk{isi{ funktiom{{ritelmi{", "P{iv{yksen t{ytyy olla t{ydellinen toistokertoimessa", "Vuosi annettu kahdesti", "Kuukausi annettu kahdesti", "P{iv{ annettu kahdesti", "Tuntematon sana tai merkki", "OMIT-komennossa on annettava kuukausi ja p{iv{", "Liian monta osittaista OMIT-komentoa", "Liian monta t{ydellist{ OMIT-komentoa", "Varoitus: PUSH-OMIT-CONTEXT ilman POP-OMIT-CONTEXTia", "Virhe tiedoston luvussa", "Pilkku puuttuu", "Virheellinen juutalainen p{iv{ys", "IIF vaatii parittoman m{{r{n argumentteja", "Varoitus: puuttuva ENDIF", "Pilkku puuttuu", "Viikonp{iv{ annettu kahdesti", "K{yt{ vain yht{ komennoista BEFORE, AFTER ja SKIP", "Sis{kk{isi{ MSG-, MSF- ja RUN-lauseita ei voi k{ytt{{ lausekkeessa", "Toistokerroin annettu kahdesti", "Delta-arvo annettu kahdesti", "Peruutusarvo annettu kahdesti", "ONCE-avainsanaa k{ytetty kahdesti. (Hah.)", "AT-sanan per{st{ puuttuu aika", "THROUGH/UNTIL-sanaa k{ytetty kahdesti", "Ep{t{ydellinen p{iv{ys", "FROM/SCANFROM-sanaa k{ytetty kahdesti", "Muuttuja", "Arvo", "*M[[RITTELEM[T\\N*", "Siirryt{{n funktioon", "Poistutaan funktiosta", "Vanhentunut", "fork() ep{onnistui - jonomuistutukset eiv{t toimi", "Tiedoston avaus ei onnistu", "Virheellinen j{rjestelm{p{iv{ys: vuosi on v{hemm{n kuin %d\n", "Tuntematon virheenetsint{tarkenne '%c'\n", "Tuntematon tarkenne '%c'\n", "Tuntematon k{ytt{j{ '%s'\n", "Ryhm{numeron vaihto %d:ksi ei onnistunut\n", "K{ytt{j{numeron vaihto %d:ksi ei onnistunut\n", "Muisti ei riit{ ymp{rist|lle\n", "Puuttuva '='-merkki", "Puuttuva muuttujanimi", "Puuttuva lauseke", "P{iv{n asetus %s:ksi ei onnitus\n", "Remind: tarkenne '-i': %s\n", "Ei viestej{.", "%d viesti({) t{m{n p{iv{n jonossa.\n", "Numero puuttuu", "Virheellinen funktio WARN-lausekkeessa", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" #endif }; #endif /* MK_GLOBALS */ /* The following is only used in init.c */ #ifdef L_IN_INIT #define L_USAGE_OVERRIDE 1 void Usage(void) { fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1998 Dianne Skoll\n", VERSION, L_LANGNAME); fprintf(ErrFp, "Copyright 1999-2000 Roaring Penguin Software Inc.\n"); #ifdef BETA fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n"); #endif #if ISOLATIN1 fprintf(ErrFp, "K\xE4ytt\xF6: remind [tarkenteet] tiedosto [p\xE4iv\xE4ys] [aika] [*toisto]\n"); fprintf(ErrFp, "Tarkenteet:\n"); fprintf(ErrFp, " -n Tulosta viestien seuraavat esiintymiskerrat yksink. muodossa\n"); fprintf(ErrFp, " -r Est\xE4 RUN-lauseiden k\xE4ytt\xF6\n"); fprintf(ErrFp, " -c[n] Tulosta n:n kuukauden kalenteri (oletus 1)\n"); fprintf(ErrFp, " -c+[n] Tulosta n:n viikon kalenteri (oletus 1)\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Aseta kalenterin leveys, tasaus ja v\xE4lit\n"); fprintf(ErrFp, " -s[+][n] Tulosta n:n kuukauden (viikon) 'yksink. kalenteri' (oletus 1)\n"); fprintf(ErrFp, " -p[n] Kuten -s, mutta tulosta rem2ps:lle sopivassa muodossa\n"); fprintf(ErrFp, " -v Laveat tulostukset\n"); fprintf(ErrFp, " -o \xC4l\xE4 noudata ONCE-lauseita\n"); fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta v\xE4litt\xE4m\xE4tt\xE4\n"); fprintf(ErrFp, " -h Suppeat tulostukset\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a \xC4l\xE4 laukaise viestej\xE4 heti - lis\xE4\xE4 ne jonoon\n"); fprintf(ErrFp, " -q \xC4l\xE4 lis\xE4\xE4 viestej\xE4 jonoon\n"); fprintf(ErrFp, " -f Laukaise viestit, pysy etualalla\n"); fprintf(ErrFp, " -z[n] K\xE4ynnisty demonina, her\xE4tys n:n (5:n) minuutin v\xE4lein\n"); #endif fprintf(ErrFp, " -d... Virheenetsint\xE4: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Ohjaa virhetulostus stdout-vuohon\n"); fprintf(ErrFp, " -b[n] Ajan ilmaisu: 0=ap/ip, 1=24 tuntia, 2=ei aikoja\n"); fprintf(ErrFp, " -x[n] SATISFY-lauseen toistoraja (oletus 150)\n"); fprintf(ErrFp, " -kcmd Suorita 'cmd' MSG-tyyppisille viesteille\n"); fprintf(ErrFp, " -g[ddd] Lajittele viestit p\xE4iv\xE4yksen, ajan ja t\xE4rkeyden mukaan\n"); fprintf(ErrFp, " -ivar=val Alusta muuttuja var arvolla val ja s\xE4ilyt\xE4 var\n"); fprintf(ErrFp, " -m Aloita kalenteri maanantaista eik\xE4 sunnuntaista\n"); exit(1); #elif IBMEXTENDED fprintf(ErrFp, "K\x84ytt\x94: remind [tarkenteet] tiedosto [p\x84iv\x84ys] [aika] [*toisto]\n"); fprintf(ErrFp, "Tarkenteet:\n"); fprintf(ErrFp, " -n Tulosta viestien seuraavat esiintymiskerrat yksink. muodossa\n"); fprintf(ErrFp, " -r Est\x84 RUN-lauseiden k\x84ytt\x94\n"); fprintf(ErrFp, " -c[n] Tulosta n:n kuukauden kalenteri (oletus 1)\n"); fprintf(ErrFp, " -c+[n] Tulosta n:n viikon kalenteri (oletus 1)\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Aseta kalenterin leveys, tasaus ja v\x84lit\n"); fprintf(ErrFp, " -s[+][n] Tulosta n:n kuukauden (viikon) 'yksink. kalenteri' (oletus 1)\n"); fprintf(ErrFp, " -p[n] Kuten -s, mutta tulosta rem2ps:lle sopivassa muodossa\n"); fprintf(ErrFp, " -v Laveat tulostukset\n"); fprintf(ErrFp, " -o \x8El\x84 noudata ONCE-lauseita\n"); fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta v\x84litt\x84m\x84tt\x84\n"); fprintf(ErrFp, " -h Suppeat tulostukset\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a \x8El\x84 laukaise viestej\x84 heti - lis\x84\x84 ne jonoon\n"); fprintf(ErrFp, " -q \x8El\x84 lis\x84\x84 viestej\x84 jonoon\n"); fprintf(ErrFp, " -f Laukaise viestit, pysy etualalla\n"); fprintf(ErrFp, " -z[n] K\x84ynnisty demonina, her\x84tys n:n (5:n) minuutin v\x84lein\n"); #endif fprintf(ErrFp, " -d... Virheenetsint\x84: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Ohjaa virhetulostus stdout-vuohon\n"); fprintf(ErrFp, " -b[n] Ajan ilmaisu: 0=ap/ip, 1=24 tuntia, 2=ei aikoja\n"); fprintf(ErrFp, " -x[n] SATISFY-lauseen toistoraja (oletus 150)\n"); fprintf(ErrFp, " -kcmd Suorita 'cmd' MSG-tyyppisille viesteille\n"); fprintf(ErrFp, " -g[ddd] Lajittele viestit p\x84iv\x84yksen, ajan ja t\x84rkeyden mukaan\n"); fprintf(ErrFp, " -ivar=val Alusta muuttuja var arvolla val ja s\x84ilyt\x84 var\n"); fprintf(ErrFp, " -m Aloita kalenteri maanantaista eik\x84 sunnuntaista\n"); exit(1); #else fprintf(ErrFp, "K{ytt|: remind [tarkenteet] tiedosto [p{iv{ys] [aika] [*toisto]\n"); fprintf(ErrFp, "Tarkenteet:\n"); fprintf(ErrFp, " -n Tulosta viestien seuraavat esiintymiskerrat yksink. muodossa\n"); fprintf(ErrFp, " -r Est{ RUN-lauseiden k{ytt|\n"); fprintf(ErrFp, " -c[n] Tulosta n:n kuukauden kalenteri (oletus 1)\n"); fprintf(ErrFp, " -c+[n] Tulosta n:n viikon kalenteri (oletus 1)\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Aseta kalenterin leveys, tasaus ja v{lit\n"); fprintf(ErrFp, " -s[+][n] Tulosta n:n kuukauden (viikon) 'yksink. kalenteri' (oletus 1)\n"); fprintf(ErrFp, " -p[n] Kuten -s, mutta tulosta rem2ps:lle sopivassa muodossa\n"); fprintf(ErrFp, " -v Laveat tulostukset\n"); fprintf(ErrFp, " -o [l{ noudata ONCE-lauseita\n"); fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta v{litt{m{tt{\n"); fprintf(ErrFp, " -h Suppeat tulostukset\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a [l{ laukaise viestej{ heti - lis{{ ne jonoon\n"); fprintf(ErrFp, " -q [l{ lis{{ viestej{ jonoon\n"); fprintf(ErrFp, " -f Laukaise viestit, pysy etualalla\n"); fprintf(ErrFp, " -z[n] K{ynnisty demonina, her{tys n:n (5:n) minuutin v{lein\n"); #endif fprintf(ErrFp, " -d... Virheenetsint{: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Ohjaa virhetulostus stdout-vuohon\n"); fprintf(ErrFp, " -b[n] Ajan ilmaisu: 0=ap/ip, 1=24 tuntia, 2=ei aikoja\n"); fprintf(ErrFp, " -x[n] SATISFY-lauseen toistoraja (oletus 150)\n"); fprintf(ErrFp, " -kcmd Suorita 'cmd' MSG-tyyppisille viesteille\n"); fprintf(ErrFp, " -g[ddd] Lajittele viestit p{iv{yksen, ajan ja t{rkeyden mukaan\n"); fprintf(ErrFp, " -ivar=val Alusta muuttuja var arvolla val ja s{ilyt{ var\n"); fprintf(ErrFp, " -m Aloita kalenteri maanantaista eik{ sunnuntaista\n"); exit(1); #endif } #endif /* L_IN_INIT */ remind-03.01.15/src/langs/french.h0000644000076400007640000004020612531375555014667 0ustar dfsdfs/***************************************************************/ /* */ /* FRENCH.H */ /* */ /* Support for the French language. */ /* */ /* Contributed by Laurent Duperval. */ /* */ /* This file is part of REMIND. */ /* */ /* REMIND is Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* This file is Copyright (C) 1993 by Laurent Duperval and */ /* Dianne Skoll. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "French" /* Day names */ #define L_SUNDAY "dimanche" #define L_MONDAY "lundi" #define L_TUESDAY "mardi" #define L_WEDNESDAY "mercredi" #define L_THURSDAY "jeudi" #define L_FRIDAY "vendredi" #define L_SATURDAY "samedi" /* Month names */ #define L_JAN "janvier" #if ISOLATIN1 #define L_FEB "f\351vrier" #else #define L_FEB "fevrier" #endif #define L_MAR "mars" #define L_APR "avril" #define L_MAY "mai" #define L_JUN "juin" #define L_JUL "juillet" #if ISOLATIN1 #define L_AUG "ao\373t" #else #define L_AUG "aout" #endif #define L_SEP "septembre" #define L_OCT "octobre" #define L_NOV "novembre" #if ISOLATIN1 #define L_DEC "d\351cembre" #else #define L_DEC "decembre" #endif /* Today and tomorrow */ #define L_TODAY "aujourd'hui" #define L_TOMORROW "demain" /* The default banner */ #define L_BANNER "Rappels pour %w, %d%s %m, %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "il y a" #define L_FROMNOW "dans" /* "in %d days' time" */ #define L_INXDAYS "dans %d jours" /* "on" as in "on date..." */ #define L_ON "le" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "s" /* Minutes, hours, at, etc */ #define L_NOW "maintenant" #if ISOLATIN1 #define L_AT "\340" #else #define L_AT "a" #endif #define L_MINUTE "minute" #define L_HOUR "heure" #define L_IS "est" #if ISOLATIN1 #define L_WAS "\351tait" #else #define L_WAS "etait" #endif #define L_AND "et" /* What to add to make "hour" plural */ #define L_HPLU "s" /* What to add to make "minute" plural */ #define L_MPLU "s" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #define L_ORDINAL_OVERRIDE \ switch(d) { \ case 1: plu = "er"; break; \ default: plu = ""; break; \ } #define L_1_OVER \ if (tdiff == 0) \ sprintf(s, L_NOW); \ else if (tdiff < 0) { \ if (mdiff == 0) \ sprintf(s, "il y a %d heure%s", hdiff, hplu); \ else if (hdiff == 0) \ sprintf(s, "il y a %d minute%s", mdiff, mplu); \ else \ sprintf(s, "il y a %d heure%s et %d minute%s", hdiff, hplu, mdiff, mplu); \ } else { \ if (mdiff == 0) \ sprintf(s, "dans %d heure%s", hdiff, hplu); \ else if (hdiff == 0) \ sprintf(s, "dans %d minute%s", mdiff, mplu); \ else \ sprintf(s, "dans %d heure%s et %d minute%s", hdiff, hplu, mdiff, mplu); \ } #define L_J_OVER if (altmode == '*') { sprintf(s, "%s, %d%s %s, %d", DayName[jul%7], d, plu, MonthName[m], y); } else { sprintf(s, "%s %s, %d%s %s, %d", L_ON, DayName[jul%7], d, plu, MonthName[m], y); } #define L_K_OVER if (altmode == '*') { sprintf(s, "%s, %d%s %s", DayName[jul%7], d, plu, MonthName[m]); } else { sprintf(s, "%s %s, %d%s %s", L_ON, DayName[jul%7], d, plu, MonthName[m]); } #endif /* L_IN_DOSUBST */ /* The next ones are used only when MK_GLOBALS is set */ #ifdef MK_GLOBALS #define L_ERR_OVERRIDE 1 EXTERN char *ErrMsg[] = { #if ISOLATIN1 "Ok", "']' manquant", "Apostrophe manquant", "Expression trop complexe - trop d'op\351rateurs", "Expression trop complexe - trop d'op\351randes", "')' manquante", "Fonction non-d\351finie", "Caract\350re ill\351gal", "Op\351rateur binaire attendu", "Manque de m\351moire", "Nombre mal form\351", "Erreur interne - 'underflow' de la pile d'op\351rateurs", "Erreur interne - 'underflow' de la pile de variables", "Impossible de convertir", "Types non-\351quivalents", "D\351bordement de date", "Erreur interne - erreur de pile", "Division par z\351ro", "Variable non d\351finie", "Fin de ligne non attendue", "Fin de fichier non attendue", "Erreur I/O", "Ligne trop longue", "Erreur interne", "Mauvaise date sp\351cifi\351e", "Pas assez d'arguments", "Trop d'arguments", "Heure mal form\351e", "Nombre trop \351lev\351", "Nombre trop bas", "Impossible d'ouvrir le fichier", "Trop d'INCLUDE imbriqu\351s", "Erreur d'analyse", "Impossible de calculer le d\351clenchement", "Trop de IF imbriqu\351s", "ELSE sans IF correspondant", "ENDIF sans IF correspondant", "Impossible d'omettre (OMIT) tous les jours", "El\351ment(s) \351tranger(s) sur la ligne", "POP-OMIT-CONTEXT sans PUSH-OMIT-CONTEXT correspondant", "RUN d\351activ\351", "Erreur de domaine", "Identificateur invalide", "Appel r\351cursif d\351tect\351", "", "Impossible de modifier une variable syst\350me", "Fonction de la librairie C ne peut repr\351senter la date/l'heure", "Tentative de red\351finition d'une fonction intrins\350que", "Impossible d'imbriquer une d\351finition de fonction dans une expression", "Pour utiliser le facteur de r\351p\351tition la date doit \352tre sp\351cifi\351e au complet", "Ann\351e sp\351cifi\351e deux fois", "Mois sp\351cifi\351 deux fois", "Jour sp\351cifi\351 deux fois", "El\351ment inconnu", "Mois et jour doivent \352tre sp\351cifi\351s dans commande OMIT", "Trop de OMITs partiels", "Trop de OMITs complets", "Attention: PUSH-OMIT-CONTEXT sans POP-OMIT-CONTEXT correspondant", "Erreur \340 la lecture du fichier", "Fin de ligne attendue", "Date h\351breuse invalide", "IIF demande nombre d'arguments impair", "Attention: ENDIF manquant", "Virgule attendue", "Jour de la semaine sp\351cifi\351 deux fois", "Utiliser un seul parmi BEFORE, AFTER ou SKIP", "Impossible d'imbriquer MSG, MSF, RUN, etc. dans une expression", "Valeur de r\351p\351tition sp\351cifi\351e deux fois", "Valeur delta sp\351cifi\351e deux fois", "Valeur de retour sp\351cifi\351e deux fois", "Mot-cl\351 ONCE utilis\351 deux fois. (Hah.)", "Heure attendue apr\350s AT", "Mot-cl\351 THROUGH/UNTIL utilis\351 deux fois", "Sp\351cification de date incompl\350te", "Mot-cl\351 FROM/SCANFROM utilis\351 deux fois", "Variable", "Valeur", "*NON-DEFINI*", "Entr\351e dans UserFN", "Sortie de UserFN", "Expir\351", "fork() \351chou\351 - impossible de faire les appels en queue", "Impossible d'acc\351der au fichier", "Date syst\350me ill\351gale: Ann\351e est inf\351rieure \340 %d\n", "Option de d\351verminage inconnue '%c'\n", "Option inconnue '%c'\n", "Usager inconnu '%s'\n", "Impossible de changer gid pour %d\n", "Impossible de changer uid pour %d\n", "Manque de m\351moire pour environnement\n", "Signe '=' manquant", "Nom de variable absent", "Expression absente", "Impossible de changer la date d'acc\350s de %s\n", "Remind: '-i' option: %s\n", "Pas de rappels.", "%d rappel(s) en file pour aujourd'hui.\n", "Nombre attendu", "Fonction ill\351gale apr\350s WARN", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" #else /* ISOLATIN1 */ "Ok", "']' manquant", "Apostrophe manquant", "Expression trop complexe - trop d'operateurs", "Expression trop complexe - trop d'operandes", "')' manquante", "Fonction non-definie", "Caractere illegal", "Operateur binaire attendu", "Manque de memoire", "Nombre mal forme", "Erreur interne - 'underflow' de la pile d'operateurs", "Erreur interne - 'underflow' de la pile de variables", "Impossible de convertir", "Types non-equivalents", "Debordement de date", "Erreur interne - erreur de pile", "Division par zero", "Variable non definie", "Fin de ligne non attendue", "Fin de fichier non attendue", "Erreur I/O", "Ligne trop longue", "Erreur interne", "Mauvaise date specifiee", "Pas assez d'arguments", "Trop d'arguments", "Heure mal formee", "Nombre trop eleve", "Nombre trop bas", "Impossible d'ouvrir le fichier", "Trop d'INCLUDE imbriques", "erreur d'analyse", "Impossible de calculer le declenchement", "Trop de IF imbriques", "ELSE sans IF correspondant", "ENDIF sans IF correspondant", "Impossible d'omettre (OMIT) tous les jours", "Element(s) etranger(s) sur la ligne", "POP-OMIT-CONTEXT sans PUSH-OMIT-CONTEXT correspondant", "RUN desactive", "Erreur de domaine", "Identificateur invalide", "Appel recursif detecte", "", "Impossible de modifier une variable systeme", "Fonction de la librairie C ne peut representer la date/l'heure", "Tentative de redefinition d'une fonction intrinseque", "Impossible d'imbriquer une definition de fonction dans une expression", "Pour utiliser le facteur de repetition la date doit etre specifiee au complet", "Annee specifiee deux fois", "Mois specifie deux fois", "Jour specifie deux fois", "Element inconnu", "Mois et jour doivent etre specifies dans commande OMIT", "Trop de OMITs partiels", "Trop de OMITs complets", "Attention: PUSH-OMIT-CONTEXT sans POP-OMIT-CONTEXT correspondant", "Erreur a la lecture du fichier", "Fin de ligne attendue", "Date hebreuse invalide", "IIF demande nombre d'arguments impair", "Attention: ENDIF manquant", "Virgule attendue", "Jour de la semaine specifie deux fois", "Utiliser un seul parmi BEFORE, AFTER ou SKIP", "Impossible d'imbriquer MSG, MSF, RUN, etc. dans une expression", "Valeur de repetition specifiee deux fois", "Valeur delta specifiee deux fois", "Valeur de retour specifiee deux fois", "Mot-cle ONCE utilise deux fois. (Hah.)", "Heure attendue apres AT", "Mot-cle THROUGH/UNTIL utilise deux fois", "Specification de date incomplete", "Mot-cle FROM/SCANFROM utilise deux fois", "Variable", "Valeur", "*NON-DEFINI*", "Entree dans UserFN", "Sortie de UserFN", "Expire", "fork() echoue - impossible de faire les appels en queue", "Impossible d'acceder au fichier", "Date systeme illegale: Annee est inferieure a %d\n", "Option de deverminage inconnue '%c'\n", "Option inconnue '%c'\n", "Usager inconnu '%s'\n", "Impossible de changer gid pour %d\n", "Impossible de changer uid pour %d\n", "Manque de memoire pour environnement\n", "Signe '=' manquant", "Nom de variable absent", "Expression absente", "Impossible de changer la date d'acces de %s\n", "Remind: '-i' option: %s\n", "Pas de rappels.", "%d rappel(s) en file pour aujourd'hui.\n", "Nombre attendu", "Fonction illegale apres WARN", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" #endif /* ISOLATIN1 */ }; #endif /* MK_GLOBALS */ /* The following is only used in init.c */ #ifdef L_IN_INIT #define L_USAGE_OVERRIDE 1 void Usage(void) { fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1998 Dianne Skoll\n", VERSION, L_LANGNAME); fprintf(ErrFp, "Copyright 1999-2000 Roaring Penguin Software Inc.\n"); #ifdef BETA fprintf(ErrFp, ">>>> BETA VERSION <<<<\n"); #endif #if ISOLATIN1 fprintf(ErrFp, "\nUtilisation: remind [options] fichier [date] [heure] [*r\351p\351tition]\n"); fprintf(ErrFp, "Options:\n"); fprintf(ErrFp, " -n Afficher la prochaine occurence des rappels en format simple\n"); fprintf(ErrFp, " -r D\351sactiver les instructions RUN\n"); fprintf(ErrFp, " -c[n] Produire un calendrier pour n (d\351faut 1) mois\n"); fprintf(ErrFp, " -c+[n] Produire un calendrier pour n (d\351faut 1) semaines\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Sp\351cifier largeur, remplissage et espacement du calendrier\n"); fprintf(ErrFp, " -s[+][n] Produire un 'calendrier simple' pour n (1) mois (semaines)\n"); fprintf(ErrFp, " -p[n] Comme -s, mais avec entr\351e compatible avec rem2ps\n"); fprintf(ErrFp, " -v Mode verbeux\n"); fprintf(ErrFp, " -o Ignorer instructions ONCE\n"); fprintf(ErrFp, " -t D\351clencher tous les rappels peu importe le delta\n"); fprintf(ErrFp, " -h Mode silencieux\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a Ne pas d\351clencher les rappels minut\351s imm\351diatement - les mettre en file\n"); fprintf(ErrFp, " -q Ne pas mettre les rappels minut\351s en file\n"); fprintf(ErrFp, " -f D\351clencher les rappels minut\351s imm\351diatement en restant en avant-plan\n"); fprintf(ErrFp, " -z[n] Entrer en mode 'daemon', r\351veil chaque n (5) minutes\n"); #endif fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Envoyer les messages de stderr \340 stdout\n"); fprintf(ErrFp, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n"); fprintf(ErrFp, " -x[n] Limite d'it\351rations pour la clause SATISFY (def=150)\n"); fprintf(ErrFp, " -kcmd Ex\351cuter 'cmd' pour les rappels de type MSG\n"); fprintf(ErrFp, " -g[ddd] Trier les rappels par date, heure et priorit\351 avant d'\351mettre\n"); fprintf(ErrFp, " -ivar=val Initialiser var \340 val et conserver var\n"); fprintf(ErrFp, " -m Commencer le calendrier avec lundi plut\364t que dimanche\n"); #else /* ISOLATIN1 */ fprintf(ErrFp, "\nUtilisation: remind [options] fichier [date] [heure] [*repetition]\n"); fprintf(ErrFp, "Options:\n"); fprintf(ErrFp, " -n Afficher la prochaine occurence des rappels en format simple\n"); fprintf(ErrFp, " -r Desactiver les instructions RUN\n"); fprintf(ErrFp, " -c[n] Produire un calendrier pour n (defaut 1) mois\n"); fprintf(ErrFp, " -c+[n] Produire un calendrier pour n (defaut 1) semaines\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Specifier largeur, remplissage et espacement du calendrier\n"); fprintf(ErrFp, " -s[+][n] Produire un 'calendrier simple' pour n (1) mois (semaines)\n"); fprintf(ErrFp, " -p[n] Comme -s, mais avec entree compatible avec rem2ps\n"); fprintf(ErrFp, " -v Mode verbeux\n"); fprintf(ErrFp, " -o Ignorer instructions ONCE\n"); fprintf(ErrFp, " -t Declencher tous les rappels peu importe le delta\n"); fprintf(ErrFp, " -h Mode silencieux\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a Ne pas declencher les rappels minutes immediatement - les mettre en file\n"); fprintf(ErrFp, " -q Ne pas mettre les rappels minutes en file\n"); fprintf(ErrFp, " -f Declencher les rappels minutes immediatement en restant en avant-plan\n"); fprintf(ErrFp, " -z[n] Entrer en mode 'daemon', reveil chaque n (5) minutes\n"); #endif fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Envoyer les messages de stderr a stdout\n"); fprintf(ErrFp, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n"); fprintf(ErrFp, " -x[n] Limite d'iterations pour la clause SATISFY (def=150)\n"); fprintf(ErrFp, " -kcmd Executer 'cmd' pour les rappels de type MSG\n"); fprintf(ErrFp, " -g[ddd] Trier les rappels par date, heure et priorite avant d'emettre\n"); fprintf(ErrFp, " -ivar=val Initialiser var a val et conserver var\n"); fprintf(ErrFp, " -m Commencer le calendrier avec lundi plutot que dimanche\n"); #endif /* ISOLATIN1 */ exit(1); } #endif /* L_IN_INIT */ remind-03.01.15/src/langs/german.h0000644000076400007640000000651212514120620014653 0ustar dfsdfs/***************************************************************/ /* */ /* GERMAN.H */ /* */ /* Support for the German language. */ /* */ /* This file was derived from a patch submitted by Wolfgang */ /* Thronicke. I don't guarantee that there are no mistakes - */ /* I don't speak German. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "German" /* Day names */ #define L_SUNDAY "Sonntag" #define L_MONDAY "Montag" #define L_TUESDAY "Dienstag" #define L_WEDNESDAY "Mittwoch" #define L_THURSDAY "Donnerstag" #define L_FRIDAY "Freitag" #define L_SATURDAY "Samstag" /* Month names */ #define L_JAN "Januar" #define L_FEB "Februar" #if ISOLATIN1 # define L_MAR "M\344rz" #else # define L_MAR "Maerz" #endif #define L_APR "April" #define L_MAY "Mai" #define L_JUN "Juni" #define L_JUL "Juli" #define L_AUG "August" #define L_SEP "September" #define L_OCT "Oktober" #define L_NOV "November" #define L_DEC "Dezember" /* Today and tomorrow */ #define L_TODAY "heute" #define L_TOMORROW "morgen" /* The default banner */ #if ISOLATIN1 # define L_BANNER "Termine f\374r %w, den %d. %m %y%o:" #else # define L_BANNER "Termine fuer %w, den %d. %m %y%o:" #endif /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "vorher" #define L_FROMNOW "von heute" /* "in %d days' time" */ #define L_INXDAYS "in %d Tagen" /* "on" as in "on date..." */ #define L_ON "am" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "en" /* Minutes, hours, at, etc */ #define L_NOW "jetzt" #define L_AT "um" #define L_MINUTE "Minute" #define L_HOUR "Stunde" #define L_IS "ist" #define L_WAS "war" #define L_AND "und" /* What to add to make "hour" plural */ #define L_HPLU "n" /* What to add to make "minute" plural */ #define L_MPLU "n" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<5) ? " nachts" : " vormittags" : (hour > 17) ? " abends" : " nachmittags"; #define L_ORDINAL_OVERRIDE plu = "."; #define L_A_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, den %d. %s %d", L_ON, DayName[jul%7], d, MonthName[m], y); } #define L_G_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s", DayName[jul%7], d, MonthName[m]); } else { sprintf(s, "%s %s, den %d. %s", L_ON, DayName[jul%7], d, MonthName[m]); } #define L_U_OVER L_A_OVER #define L_V_OVER L_G_OVER #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/icelandic.h0000644000076400007640000000465212514120613015322 0ustar dfsdfs/***************************************************************/ /* */ /* ICELANDIC.H */ /* */ /* Support for the Icelandic language. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* Translated by Bjrn Davsson (bjossi@snerpa.is) */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Icelandic" /* Day names */ #define L_SUNDAY "sunnudagur" #define L_MONDAY "mnudagur" #define L_TUESDAY "rijudagur" #define L_WEDNESDAY "mivikudagur" #define L_THURSDAY "fimmtudagur" #define L_FRIDAY "fstudagur" #define L_SATURDAY "laugardagur" /* Month names */ #define L_JAN "janar" #define L_FEB "febrar" #define L_MAR "mars" #define L_APR "aprl" #define L_MAY "ma" #define L_JUN "jn" #define L_JUL "jl" #define L_AUG "gst" #define L_SEP "september" #define L_OCT "oktber" #define L_NOV "nvember" #define L_DEC "desember" /* Today and tomorrow */ #define L_TODAY " dag" #define L_TOMORROW " morgun" /* The default banner */ #define L_BANNER "Minnisatrii: %w, %d%s %m, %y%o:" /* "am" and "pm" */ #define L_AM "fh" #define L_PM "eh" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "san" #define L_FROMNOW "fr v n" /* "in %d days' time" */ #define L_INXDAYS "eftir %d daga" /* "on" as in "on date..." */ #define L_ON "ann" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "a" /* Minutes, hours, at, etc */ #define L_NOW "nna" #define L_AT "kl." #define L_MINUTE "mntu" #define L_HOUR "klukkustund" #define L_IS "er" #define L_WAS "var" #define L_AND "og" /* What to add to make "hour" plural */ #define L_HPLU "ir" /* What to add to make "minute" plural */ #define L_MPLU "r" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/italian.h0000644000076400007640000000762212514120606015032 0ustar dfsdfs/***************************************************************/ /* */ /* ITALIAN.H */ /* */ /* Support for the Italian language. */ /* */ /* This file is part of REMIND. */ /* It is Copyright (C) 1996 by Valerio Aimale */ /* */ /* Remind is copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Italian" /* Day names */ #if ISOLATIN1 #define L_SUNDAY "Domenica" #define L_MONDAY "Luned\354" #define L_TUESDAY "Marted\354" #define L_WEDNESDAY "Mercoled\354" #define L_THURSDAY "Gioved\354" #define L_FRIDAY "Venerd\354" #define L_SATURDAY "Sabato" #else /* ISOLATIN1 */ #define L_SUNDAY "Domenica" #define L_MONDAY "Lunedi`" #define L_TUESDAY "Martedi`" #define L_WEDNESDAY "Mercoledi`" #define L_THURSDAY "Giovedi`" #define L_FRIDAY "Venerdi`" #define L_SATURDAY "Sabato" #endif /* ISOLATIN */ /* Month names */ #define L_JAN "Gennaio" #define L_FEB "Febbraio" #define L_MAR "Marzo" #define L_APR "Aprile" #define L_MAY "Maggio" #define L_JUN "Giugno" #define L_JUL "Luglio" #define L_AUG "Agosto" #define L_SEP "Settembre" #define L_OCT "Ottobre" #define L_NOV "Novembre" #define L_DEC "Dicembre" /* Today and tomorrow */ #define L_TODAY "oggi" #define L_TOMORROW "domani" /* The default banner */ #define L_BANNER "Promemoria per %w, %d %m %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "fa" #define L_FROMNOW "da oggi" /* "in %d days' time" */ #define L_INXDAYS "fra %d giorni" /* "on" as in "on date..." */ #define L_ON "" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ /* Minutes, hours, at, etc */ #define L_NOW "ora" #define L_AT "alle" #define L_MINUTE "minut" #define L_HOUR "or" #if ISOLATIN1 #define L_IS "\350" #else /* ISOLATIN1 */ #define L_IS "e`" #endif/* ISOLATIN1 */ #define L_WAS "era" #define L_AND "e" /* What to add to make "hour" plural */ #define L_HPLU "s" /* What to add to make "minute" plural */ #define L_MPLU "s" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #define L_P_OVER sprintf(s, (diff == 1 ? "o" : "i")); #define L_Q_OVER sprintf(s, (diff == 1 ? "a" : "e")); #define L_HPLU_OVER hplu = (hdiff == 1 ? "a" : "e"); #define L_MPLU_OVER mplu = (mdiff == 1 ? "o" : "i"); #define L_A_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d,\ MonthName[m], y); #define L_C_OVER sprintf(s, "%s", DayName[jul%7]); #define L_E_OVER sprintf(s, "%02d%c%02d%c%04d", d, DateSep,\ m+1, DateSep, y); #define L_F_OVER sprintf(s, "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y); #define L_G_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, MonthName[m]); #define L_H_OVER sprintf(s, "%02d%c%02d", d, DateSep, m+1); #define L_I_OVER sprintf(s, "%02d%c%02d", m+1, DateSep, d); #define L_J_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d, \ MonthName[m], y); #define L_K_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, \ MonthName[m]); #define L_L_OVER sprintf(s, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d); #define L_U_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d, \ MonthName[m], y); #define L_V_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, \ MonthName[m]); #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/norwgian.h0000644000076400007640000000640712514120602015231 0ustar dfsdfs/***************************************************************/ /* */ /* NORWGIAN.H */ /* */ /* Support for the Norwegian language. */ /* */ /* This file is part of REMIND. */ /* This file is Copyright (C) 1993 by Trygve Randen. */ /* Remind is Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Norwegian" /* Day names */ #if ISOLATIN1 # define L_SUNDAY "S\370ndag" #else # define L_SUNDAY "Soendag" #endif #define L_MONDAY "Mandag" #define L_TUESDAY "Tirsdag" #define L_WEDNESDAY "Onsdag" #define L_THURSDAY "Torsdag" #define L_FRIDAY "Fredag" #if ISOLATIN1 # define L_SATURDAY "L\370rdag" #else # define L_SATURDAY "Loerdag" #endif /* Month names */ #define L_JAN "Januar" #define L_FEB "Februar" #define L_MAR "Mars" #define L_APR "April" #define L_MAY "Mai" #define L_JUN "Juni" #define L_JUL "Juli" #define L_AUG "August" #define L_SEP "September" #define L_OCT "Oktober" #define L_NOV "November" #define L_DEC "Desember" /* Today and tomorrow */ #define L_TODAY "i dag" #define L_TOMORROW "i morgen" /* The default banner */ #if ISOLATIN1 # define L_BANNER "P\345minnelse for %w, %d. %m, %y%o:" #else # define L_BANNER "Paaminnelse for %w, %d. %m, %y%o:" #endif /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "siden" #if ISOLATIN1 # define L_FROMNOW "fra n\345" #else # define L_FROMNOW "fra naa" #endif /* "in %d days' time" */ #define L_INXDAYS "om %d dager" /* "on" as in "on date..." */ #define L_ON "den" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "er" /* Minutes, hours, at, etc */ #if ISOLATIN1 # define L_NOW "n\345" #else # define L_NOW "naa" #endif #define L_AT "kl." #define L_MINUTE "minutt" #define L_HOUR "time" #define L_IS "er" #define L_WAS "var" #define L_AND "og" /* What to add to make "hour" plural */ #define L_HPLU "r" /* What to add to make "minute" plural */ #define L_MPLU "er" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #define L_ORDINAL_OVERRIDE plu = "."; #define L_A_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, den %d. %s %d", L_ON, DayName[jul%7], d, MonthName[m], y); } #define L_G_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s", DayName[jul%7], d, MonthName[m]); } else { sprintf(s, "%s %s, den %d. %s", L_ON, DayName[jul%7], d, MonthName[m]); } #define L_U_OVER L_A_OVER #define L_V_OVER L_G_OVER #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/polish.h0000644000076400007640000004214112531375571014716 0ustar dfsdfs/***************************************************************/ /* */ /* POLISH.H */ /* */ /* Support for the Polish language. */ /* */ /* This file was submitted by Jerzy Sobczyk. I don't */ /* guarantee that there are no mistakes - I don't speak */ /* Polish. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Polish" /* Day names */ #if ISOLATIN1 # define L_SUNDAY "Niedziela" # define L_MONDAY "Poniedzia\263ek" # define L_TUESDAY "Wtorek" # define L_WEDNESDAY "\246roda" # define L_THURSDAY "Czwartek" # define L_FRIDAY "Pi\261tek" # define L_SATURDAY "Sobota" #else # define L_SUNDAY "Niedziela" # define L_MONDAY "Poniedzialek" # define L_TUESDAY "Wtorek" # define L_WEDNESDAY "Sroda" # define L_THURSDAY "Czwartek" # define L_FRIDAY "Piatek" # define L_SATURDAY "Sobota" #endif /* Month names */ #if ISOLATIN1 # define L_JAN "Stycze\361" # define L_FEB "Luty" # define L_MAR "Marzec" # define L_APR "Kwiecie\361" # define L_MAY "Maj" # define L_JUN "Czerwiec" # define L_JUL "Lipiec" # define L_AUG "Sierpie\361" # define L_SEP "Wrzesie\361" # define L_OCT "Pa\274dziernik" # define L_NOV "Listopad" # define L_DEC "Grudzie\361" #else # define L_JAN "Styczen" # define L_FEB "Luty" # define L_MAR "Marzec" # define L_APR "Kwiecien" # define L_MAY "Maj" # define L_JUN "Czerwiec" # define L_JUL "Lipiec" # define L_AUG "Sierpien" # define L_SEP "Wrzesien" # define L_OCT "Pazdziernik" # define L_NOV "Listopad" # define L_DEC "Grudzien" #endif /* Today and tomorrow */ #define L_TODAY "dzisiaj" #define L_TOMORROW "jutro" /* The default banner */ #define L_BANNER "Terminarz na %w, %d. %m %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "temu" #define L_FROMNOW "od teraz" /* "in %d days' time" */ #define L_INXDAYS "za %d dni" /* "on" as in "on date..." */ #define L_ON "-" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "" /* Minutes, hours, at, etc */ #define L_NOW "teraz" #define L_AT "o" #define L_MINUTE "minut" #define L_HOUR "godzin" #if ISOLATIN1 # define L_IS "b\352dzie" # define L_WAS "by\263o" #else # define L_IS "bedzie" # define L_WAS "bylo" #endif #define L_AND "i" /* What to add to make "hour" or "minute" plural */ #if ISOLATIN1 #define L_NPLU( N ) ((N == 1) ? "\352" : ((N==12) || (N==13) || (N==14)) ? "" : \ ((N%10==2) || (N%10==3) || (N%10==4)) ? "y" : "" ) #else #define L_NPLU( N ) ((N == 1) ? "e" : ((N==12) || (N==13) || (N==14)) ? "" : \ ((N%10==2) || (N%10==3) || (N%10==4)) ? "y" : "" ) #endif /* What to add to make "hour" plural */ #define L_HPLU L_NPLU( hdiff ) /* What to add to make "minute" plural */ #define L_MPLU L_NPLU( mdiff ) /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #if ISOLATIN1 #define L_AMPM_OVERRIDE(ampm, hour) \ ampm = (hour<12) ? \ (hour<5) ? " w nocy" \ : (hour<10) ? " rano" \ : " przed po\263udniem" \ : (hour<18) ? " po po\263udniu" \ : (hour<22) ? " wieczorem" \ : " w nocy"; #else #define L_AMPM_OVERRIDE(ampm, hour) \ ampm = (hour<12) ? \ (hour<5) ? " w nocy" \ : (hour<10) ? " rano" \ : " przed poludniem" \ : (hour<18) ? " po poludniu" \ : (hour<22) ? " wieczorem" \ : " w nocy"; #endif #define L_ORDINAL_OVERRIDE plu = ""; #define L_A_OVER if (altmode == '*') { sprintf(s, "%s, %d. %s %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, %d. %s %d", L_ON, DayName[jul%7], d, MonthName[m], y); } #define L_G_OVER if (altmode == '*') { sprintf(s, "%s, %d. %s", DayName[jul%7], d, MonthName[m]); } else { sprintf(s, "%s %s, %d. %s", L_ON, DayName[jul%7], d, MonthName[m]); } #define L_U_OVER L_A_OVER #define L_V_OVER L_G_OVER #endif /* L_IN_DOSUBST */ #define L_0_OVER sprintf(s, L_HPLU); #define L_9_OVER sprintf(s, L_MPLU); #define L_1_OVER \ if (tdiff == 0) \ sprintf(s, L_NOW); \ else if (tdiff > 0) \ { \ if (hdiff == 0) \ sprintf(s, "za %d %s%s", mdiff, L_MINUTE, L_MPLU); \ else if (mdiff == 0) \ sprintf(s, "za %d %s%s", hdiff, L_HOUR, L_HPLU); \ else \ sprintf(s, "za %d %s%s %s %d %s%s", hdiff, L_HOUR, L_HPLU, \ L_AND, mdiff, L_MINUTE, L_MPLU); \ } \ else \ { \ if (hdiff == 0) \ sprintf(s, "%d %s%s temu", mdiff, L_MINUTE, L_MPLU); \ else if (mdiff == 0) \ sprintf(s, "%d %s%s temu", hdiff, L_HOUR, L_HPLU); \ else \ sprintf(s, "%d %s%s %s %d %s%s temu", hdiff, L_HOUR, L_HPLU, \ L_AND, mdiff, L_MINUTE, L_MPLU); \ } /* The next ones are used only when MK_GLOBALS is set */ #ifdef MK_GLOBALS #define L_ERR_OVERRIDE 1 EXTERN char *ErrMsg[] = { #if ISOLATIN1 "OK", "Brakuj\261cy ']'", "Brakuj\261cy nawias", "Zbyt skomplikowane wyra\277enie - za du\277o operator\363w", "Zbyt skomplikowane wyra\277enie - za du\277o argument\363w", "Brakuj\261cy ')'", "Nie zdefiniowana funkcja", "Nielegalny znak", "Spodziewany operator binarny", "Brak pami\352ci", "Niepoprawny numer", "Pusty stos operator\363w - b\263\261d wewn\352trzny", "Pusty stos zmiennych - b\263\261d wewn\352trzny", "Niemo\277liwa konwersja", "B\263\261d typu", "Nadmiar daty", "B\263\261d stosu - b\263\261d wewn\352trzny", "Dzielenie przez zero", "Niezdefiniowana zmienna", "Niespodziewany koniec linii", "Niespodziewany koniec pliku", "B\263\261d wejscia/wyjscia", "Za d\263uga linia", "B\263\261d wewn\352trzny", "Z\263a specyfikacja daty", "Za ma\263o argument\363w", "Za du\277o argument\363w", "Nieprawid\263owy czas", "Liczba za du\277a", "Liczba za ma\263a", "Nie mog\352 otworzy\346 pliku", "Zbyt zagnie\277d\277one INCLUDE", "B\263\261d sk\263adniowy", "Nie mog\352 obliczy\346 przypomnienia", "Zbyt zagnie\277d\277one IF", "ELSE bez IF do pary", "ENDIF bez IF do pary", "Nie mog\352 omin\261\346 (OMIT) wszystkich dni", "Niespodziewany wyraz w lini", "POP-OMIT-CONTEXT bez PUSH-OMIT-CONTEXT", "Komenda RUN zablokowana", "B\263\261d dziedziny", "Niepoprawny identyfikator", "Wykryto rekursywne wywo\263anie funkcji", "", "Nie mog\352 zmieni\346 zmiennej systemowej", "Funkcja biblioteki C nie mo\277e reprezentowac daty/czasu", "Pr\363ba redefinicji funkcji wbudowanej", "Nie wolno zagnie\277d\277a\346 definicji funkcji w wyra\277eniu", "Aby u\277yc powt\363rzenia trzeba w pe\263ni wyspecyfikowa\346 dat\352", "Rok podany dw\363krotnie", "Miesi\261c podany dw\363krotnie", "Dzie\361 podany dw\363krotnie", "Nieznane s\263owo", "W komendzie OMIT trzeba poda\346 miesi\261c i dzie\361", "Za du\277o cz\352\266ciowych komend OMIT", "Za du\277o pe\263nych komend OMIT", "Ostrze\277enie: PUSH-OMIT-CONTEXT bez POP-OMIT-CONTEXT", "B\263\261d odczytu pliku", "Oczekiwany koniec linii", "B\263\352dna data hebrajska", "IIF wymaga nieparzystej liczby argument\363w", "Ostrze\277enie: Brakujacy ENDIF", "Oczekiwany przecinek", "Dzie\361 tygodnia podany dw\363krotnie", "Dozwolone tylko jedno z: BEFORE, AFTER i SKIP", "Nie mo\277na zagnie\277d\277a\346 MSG, MSF, RUN, itp. w wyra\277eniu", "Warto\266\346 powtorzenia podana dw\363krotnie", "Warto\266\346 r\363\277nicy podana dw\363krotnie", "Warto\266\346 cofni\352cia podana dw\363krotnie", "S\263owo ONCE u\277yte dw\363krotnie.", "Po AT oczekiwany jest czas", "S\263owo THROUGH/UNTIL u\277yte dw\363krotnie", "Niekompletna specyfikacja daty", "S\263owo FROM/SCANFROM u\277yte dw\363krotnie", "Zmienna", "Warto\266\346", "*NIE ZDEFINIOWANE*", "Pocz\261tek UserFN", "Koniec UserFN", "Przemine\263o", "Niepowodzenie w funkcji fork() - nie mog\352 kolejkowa\346 przypomnie\361", "Nie ma dost\352pu do pliku", "B\263\352dna data systemowa: Rok mniejszy ni\277 %d\n", "Nieznana flaga odpluskwiania '%c'\n", "Nieznana opcja '%c'\n", "Nieznany u\277ytkownik '%s'\n", "Nie mog\352 zmieni\346 gid na %d\n", "Nie mog\352 zmieni\346 uid na %d\n", "Brak pami\352ci na zmienne \266rodowiska\n", "Brak znaku '='", "Brak nazwy zmiennej", "Brak wyra\277enia", "Nie mog\352 zmieni\346 daty dost\352pu pliku %s\n", "Remind: '-i' option: %s\n", "Brak przypomnie\361.", "%d Przypomnienia zakolejkowane na p\363\274niej.\n", "Spodziewana liczba", "Illegal function in WARN clause (NEEDS TRANSLATION TO POLISH)", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" #else /* ISOLATIN1 */ "OK", "Brakujacy ']'", "Brakujacy nawias", "Zbyt skomplikowane wyrazenie - za duzo operatorow", "Zbyt skomplikowane wyrazenie - za duzo argumentow", "Brakujacy ')'", "Niezdefiniowana funkcja", "Nielegalny znak", "Spodziewany operator binarny", "Brak pamieci", "Niepoprawny numer", "Pusty stos operatorow - blad wewnetrzny", "Pusty stos zmiennych - blad wewnetrzny", "Niemozliwa konwersja", "Blad typu", "Nadmiar daty", "Blad stosu - blad wewnetrzny", "Dzielenie przez zero", "Niezdefiniowana zmienna", "Niespodziewany koniec linii", "Niespodziewany koniec pliku", "Blad wejscia/wyjscia", "Za dluga linia", "Blad wewnetrzny", "Zla specyfikacja daty", "Za malo argumentow", "Za duzo argumentow", "Nieprawidlowy czas", "Liczba za duza", "Liczba za mala", "Nie moge otworzyc pliku", "INCLUDE zbyt zagniezdzone", "Blad skladniowy", "Nie moge obliczyc przypomnienia", "Zbyt zagniezdzone IF", "ELSE bez IF do pary", "ENDIF bez IF do pary", "Nie moge ominac (OMIT) wszystkich dni", "Niespodziewany wyraz w lini", "POP-OMIT-CONTEXT bez PUSH-OMIT-CONTEXT", "Komenda RUN zablokowana", "Blad dziedziny", "Niepoprawny identyfikator", "Wykryto rekursywne wywolanie funkcji", "", "Nie moga zmienic zmiennej systemowej", "Funkcja biblioteki C nie moze reprezentowac daty/czasu", "Proba redefinicji funkcji wbudowanej", "Nie wolno zagniezdzac definicji funkcji w wyrazeniu", "Aby uzyc powtorzenia trzeba w pelni wyspecyfikowac date", "Rok podany dwokrotnie", "Miesiac podany dwokrotnie", "Dzien podany dwokrotnie", "Nieznane slowo", "W komendzie OMIT trzeba podac miesiac i dzien", "Za duzo czesciowych komend OMIT", "Za duzo pelnych komend OMIT", "ostrzezenie: PUSH-OMIT-CONTEXT bez POP-OMIT-CONTEXT", "Blad odczytu pliku", "Oczekiwany koniec linii", "Bledna data hebrajska", "IIF wymaga nieparzystej liczby argumentow", "Ostrzezenie: Brakujacy ENDIF", "Oczekiwany przecinek", "Dzien tygodnia podany dwokrotnie", "Dozwolone tylko jedno z: BEFORE, AFTER i SKIP", "Nie mozna zagniezdzac MSG, MSF, RUN, itp. w wyrazeniu", "Wartosc powtorzenia podana dwokrotnie", "Wartosc roznicy podana dwokrotnie", "Wartosc cofniecia podana dwokrotnie", "Slowo ONCE uzyte dwokrotnie.", "Po AT oczekiwany jest czas", "Slowo THROUGH/UNTIL uzyte dwokrotnie", "Niekompletna specyfikacja daty", "Slowo FROM/SCANFROM uzyte dwokrotnie", "Zmienna", "Wartosc", "*UNDEFINED*", "Poczatek UserFN", "Koniec UserFN", "Przeminelo", "niepowodzenie w funkcji fork() - nie moge kolejkowac przypomnien", "Nie ma dostepu do pliku", "Bledna data systemowa: Rok mniejszy niz %d\n", "Nieznana flaga odpluskwiania '%c'\n", "Nieznana opcja '%c'\n", "Nieznany uzytkownik '%s'\n", "Nie moge zmienic gid na %d\n", "Nie moge zmienic uid na %d\n", "Brak pamieci na zmienne srodowiska\n", "Brak znaku '='", "Brak nazwy zmiennej", "Brak wyrazenia", "Nie moge zmienic daty dostepu pliku %s\n", "Remind: '-i' option: %s\n", "Brak przypomnien.", "%d Przypomnienia zakolejkowane na pozniej.\n", "Spodziewana liczba", "Illegal function in WARN clause (NEEDS TRANSLATION TO POLISH)", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" #endif /* ISOLATIN1 */ }; #endif /* MK_GLOBALS */ /* The following is only used in init.c */ #ifdef L_IN_INIT #define L_USAGE_OVERRIDE 1 void Usage(void) { fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1998 Dianne Skoll\n", VERSION, L_LANGNAME); fprintf(ErrFp, "Copyright 1999-2000 Roaring Penguin Software Inc.\n"); #ifdef BETA fprintf(ErrFp, ">>>> BETA VERSION <<<<\n"); #endif #if ISOLATIN1 fprintf(ErrFp, "\nSpos\363b u\277ycia: remind [opcje] plik [data] [czas] [*powt\363rzenie]\n"); fprintf(ErrFp, "Opcje:\n"); fprintf(ErrFp, " -n Wypisz nast\352pne przypomnienia w prostym formacie\n"); fprintf(ErrFp, " -r Zablokuj dyrektywy RUN\n"); fprintf(ErrFp, " -c[n] Wypisz kalendarz na n (domy\266lnie 1) miesi\352cy\n"); fprintf(ErrFp, " -c+[n] Wypisz kalendarz na n (domy\266lnie 1) tygodni\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Ustaw szeroko\266\346, wype\263nienie i odst\352py w kalendarzu\n"); fprintf(ErrFp, " -s[+][n] Wypisz uproszczony kalendarz na n (1) miesi\352cy (tygodni)\n"); fprintf(ErrFp, " -p[n] To samo co -s, ale kompatybilne z rem2ps\n"); fprintf(ErrFp, " -v Obszerniejsze komentarze\n"); fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n"); fprintf(ErrFp, " -t Odpal wszystkie przysz\263e przypomnienia niezale\277nie od delty\n"); fprintf(ErrFp, " -h Praca bezszmerowa\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a Nie odpalaj przyponie\361 czasowych - kolejkuj je\n"); fprintf(ErrFp, " -q Nie kolejkuj przyponie\361 czasowych\n"); fprintf(ErrFp, " -f Nie przechod\274 do pracy w tle\n"); fprintf(ErrFp, " -z[n] Pracuj jako demon, budz\261c si\352 co n (5) minut\n"); #endif fprintf(ErrFp, " -d... Odpluskwianie: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Komunikaty o b\263\352dach skieruj na stdout\n"); fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=\277aden\n"); fprintf(ErrFp, " -x[n] Limit powt\363rze\361 klauzuli SATISFY (domy\266lnie=150)\n"); fprintf(ErrFp, " -kcmd Wywo\263aj 'cmd' dla przypomnie\361 typu MSG\n"); fprintf(ErrFp, " -g[ddd] Sortuj przypomnienia wed\263ug daty, czasu i priorytetu\n"); fprintf(ErrFp, " -ivar=val Zainicjuj zmienn\261 var warto\266cia val i zachowaj ja\n"); fprintf(ErrFp, " -m Rozpocznij kalendarz od poniedzia\263ku zamiast od niedzieli\n"); #else /* ISOLATIN1 */ fprintf(ErrFp, "\nSposob uzycia: remind [opcje] plik [data] [czas] [*powtorzenie]\n"); fprintf(ErrFp, "Opcje:\n"); fprintf(ErrFp, " -n Wypisz nastepne przypomnienia w prostym formacie\n"); fprintf(ErrFp, " -r Zablokuj dyrektywy RUN\n"); fprintf(ErrFp, " -c[n] Wypisz kalendarz na n (domyslnie 1) miesiecy\n"); fprintf(ErrFp, " -c+[n] Wypisz kalendarz na n (domyslnie 1) tygodni\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Ustaw szerokosc, wypelnienie i odstepy w kalendarzu\n"); fprintf(ErrFp, " -s[+][n] Wypisz uproszczony kalendarz na n (1) miesiecy (tygodni)\n"); fprintf(ErrFp, " -p[n] To samo co -s, ale kompatybilne z rem2ps\n"); fprintf(ErrFp, " -v Obszerniejsze komentarze\n"); fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n"); fprintf(ErrFp, " -t Odpal wszystkie przyszle przypomnienia niezaleznie od delty\n"); fprintf(ErrFp, " -h Praca bezszmerowa\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a Nie odpalaj przyponien czasowych - kolejkuj je\n"); fprintf(ErrFp, " -q Nie kolejkuj przyponien czasowych\n"); fprintf(ErrFp, " -f Nie przechodz do pracy w tle\n"); fprintf(ErrFp, " -z[n] Pracuj jako demon, budzac sie co n (5) minut\n"); #endif fprintf(ErrFp, " -d... Odpluskwianie: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Komunikaty o bledach skieruj na stdout\n"); fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=zaden\n"); fprintf(ErrFp, " -x[n] Limit powtorzen klauzuli SATISFY (domyslnie=150)\n"); fprintf(ErrFp, " -kcmd Wywolaj 'cmd' dla przypomnien typu MSG\n"); fprintf(ErrFp, " -g[ddd] Sortuj przypomnienia wedlug daty, czasu i priorytetu\n"); fprintf(ErrFp, " -ivar=val Zainicjuj zmienna var wartoscia val i zachowaj ja\n"); fprintf(ErrFp, " -m Rozpocznij kalendarz od poniedzialku zamiast od niedzieli\n"); #endif /* ISOLATIN1 */ exit(1); } #endif /* L_IN_INIT */ remind-03.01.15/src/langs/portbr.h0000644000076400007640000002450212531375537014733 0ustar dfsdfs/***************************************************************/ /* */ /* PORTBR.H */ /* */ /* Support for the Brazilian Portuguese Language. */ /* */ /* Contributed by Marco Paganini (paganini@ism.com.br). */ /* */ /* This file is part of REMIND. */ /* */ /* REMIND is Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* This file is Copyright (C) 1996 by Marco Paganini and */ /* Dianne Skoll. */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Brazilian Portuguese" /* Day names */ #define L_SUNDAY "domingo" #define L_MONDAY "segunda" #define L_TUESDAY "terca" #define L_WEDNESDAY "quarta" #define L_THURSDAY "quinta" #define L_FRIDAY "sexta" #define L_SATURDAY "sabado" /* Month names */ #define L_JAN "janeiro" #define L_FEB "fevereiro" #define L_MAR "marco" #define L_APR "abril" #define L_MAY "maio" #define L_JUN "junho" #define L_JUL "julho" #define L_AUG "agosto" #define L_SEP "setembro" #define L_OCT "outubro" #define L_NOV "novembro" #define L_DEC "dezembro" /* Today and tomorrow */ #define L_TODAY "hoje" #define L_TOMORROW "amanha" /* The default banner */ #define L_BANNER "Avisos para %w, %d de %m de %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Ago and from now */ #define L_AGO "atras" #define L_FROMNOW "adiante" /* "in %d days' time" */ #define L_INXDAYS "em %d dias" /* "on" as in "on date..." */ #define L_ON "em" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "s" /* Minutes, hours, at, etc */ #define L_NOW "agora" #define L_AT "as" #define L_MINUTE "minuto" #define L_HOUR "hora" #define L_IS "sao" #define L_WAS "eram" #define L_AND "e" /* What to add to make "hour" plural */ #define L_HPLU "s" /* What to add to make "minute" plural */ #define L_MPLU "s" /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #define L_ORDINAL_OVERRIDE plu = ""; /* Portuguese weekdays must be treated separately */ #define _ON_WEEKDAY(x) ((x % 7) < 2) ? "no" : "na" #define L_A_OVER \ sprintf(s, "%s %s, %d de %s de %d", _ON_WEEKDAY(jul), DayName[jul%7], d, MonthName[m], y); #define L_C_OVER \ sprintf(s, "%s %s", _ON_WEEKDAY(jul), DayName[jul%7]); #define L_G_OVER \ sprintf(s, "%s %s, %d %s", _ON_WEEKDAY(jul), DayName[jul%7], d, MonthName[m]); #define L_J_OVER \ sprintf(s, "%s %s, %d de %s de %d", _ON_WEEKDAY(jul), DayName[jul%7], d, MonthName[m], y); #define L_K_OVER \ sprintf(s, "%s %s, %d de %s", _ON_WEEKDAY(jul), DayName[jul%7], d, MonthName[m]); /* Portuguese does not use some suffixes, some some %u and %j are the same */ #define L_U_OVER \ sprintf(s, "%s %s, %d de %s de %d", _ON_WEEKDAY(jul), DayName[jul%7], d, MonthName[m], y); #define L_V_OVER \ sprintf(s, "%s %s, %d de %s", _ON_WEEKDAY(jul), DayName[jul%7], d, MonthName[m]); #define L_1_OVER \ { \ if (tdiff == 0) \ sprintf(s, L_NOW); \ else \ if (hdiff == 0) \ { \ if (mdiff > 0) \ sprintf(s, "em %d %s%s", mdiff, L_MINUTE, mplu); \ else \ sprintf(s, "%d %s%s atras", mdiff, L_MINUTE, mplu); \ } \ else if (mdiff == 0) \ { \ if (hdiff > 0) \ sprintf(s, "em %d %s%s", hdiff, L_HOUR, hplu); \ else \ sprintf(s, "%d %s%s atras", hdiff, L_HOUR, hplu); \ } else { \ if (tdiff > 0) \ sprintf(s, "em %d %s%s %s %d %s%s", hdiff, L_HOUR, hplu, L_AND, mdiff, L_MINUTE, mplu); \ else \ sprintf(s, "%d %s%s %s %d %s%s atras", hdiff, L_HOUR, hplu, L_AND, mdiff, L_MINUTE, mplu); \ } \ } #endif /* L_IN_DOSUBST */ /* The next ones are used only when MK_GLOBALS is set */ #ifdef MK_GLOBALS #define L_ERR_OVERRIDE 1 EXTERN char *ErrMsg[] = { "Ok", "Falta um ']'", "Falta uma aspa", "Expressao muito complexa - muitos operadores", "Expressao muito complexa - muitos operandos", "Falta um ')'", "Funcao nao definida", "Caracter ilegal", "Esperando operador binario", "Sem memoria", "Numero mal-formado", "Op stack underflow - erro interno", "Va stack underflow - erro interno", "Nao consigo fazer 'coerce'", "Type mismatch", "Overflow na data", "Erro de stack - erro interno", "Divisao por zero", "Variavel nao definida", "Fim da linha nao esperado", "Fim de arquivo nao esperado", "Erro de I/O", "Linha muito longa", "Erro interno", "Especificacao de data invalida", "Argumentos insuficientes", "Argumentos em excesso", "Hora mal-formada", "Numero muito grande", "Numero muito pequeno", "Nao consigo abrir o arquivo", "Ninho de INCLUDEs muito profundo", "Erro de parsing", "Nao consigo computar o 'trigger'", "Muitos IFs aninhados", "ELSE sem o IF correspondente", "ENDIF sem o IF correspondente", "Nao se pode usar OMIT para todos os dias da semana", "Token nao reconhecido na linha", "POP-OMIT-CONTEXT sem PUSH-OMIT-CONTEXT correspondente", "RUN desabilitado", "Erro de dominio", "Identificados invalido", "Chamada de funcao recursiva detectada", "", "Nao posso modificar variavel de sistema", "Funcao da biblioteca C nao pode representar data/hora", "Tentativa de redefinir funcao interna", "Nao e' possivel aninhar definicao de funcao em expressao", "Data deve ser completamente especificada para usar o fator de REPEAT", "Ano especificado duas vezes", "Mes especificado duas vezes", "Dia especificado duas vezes", "Token desconhecido", "Mes e dia devem ser especificados no comando OMIT", "Muitos OMITs parciais", "Muitos OMITs full", "Aviso: PUSH-OMIT-CONTEXT sem POP-OMIT-CONTEXT correspondente", "Erro na leitura do arquivo", "Aguardando fim do arquivo", "Data hebraica invalida", "IIF necessita de numero impar de argumentos", "Warning: ENDIF faltando", "Esperando virgula", "Dia da semana especificado duas vezes", "Use apenas um de BEFORE, AFTER ou SKIP", "Nao e possivel aninhar MSG, MSF, RUN, etc. em expressoes", "Valor de Repeat especificado duas vezes", "Valor de Delta especificado duas vezes", "Valor de Back especificado duas vezes", "ONCE usado duas vezes (Eheheh)", "Esperando hora apos AT", "Keyword THROUGH/UNTIL usada duas vezes", "Especificacao de data incompleta", "Keyword FROM/SCANFROM usada duas vezes", "Variavel", "Valor", "*INDEFINIDO*", "Entrando UserFN", "Saindo UserFN", "Expirou", "fork() falhou - Nao posso processar compromissos na fila", "Nao consigo acessar o arquivo", "Data do sistema ilegal: Ano e menor que %d\n", "Flag de debug desconhecido '%c'\n", "Opcao desconhecida '%c'\n", "Usuario desconhecido '%s'\n", "Nao consigo mudar gid para %d\n", "Nao consigo mudar uid para %d\n", "Sem memoria para o environment\n", "Falta o sinal de '='", "Falta o nome da variavel", "Falta a expressao", "Nao consigo resetar a data de acesso de %s\n", "Remind: '-i' opcao: %s\n", "Sem compromissos.", "%d compromisso(s) colocados na fila para mais tarde.\n", "Esperando numero", "Funcao ilegal na clausula WARN", "Can't convert between time zones", "No files matching *.rem", "String too long", "Time specified twice" }; #endif /* MK_GLOBALS */ /* The following is only used in init.c */ #ifdef L_IN_INIT #define L_USAGE_OVERRIDE 1 void Usage(void) { fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-1998 Dianne Skoll\n", VERSION, L_LANGNAME); fprintf(ErrFp, "(C) 1999-2000 Roaring Penguin Software Inc.\n"); #ifdef BETA fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n"); #endif fprintf(ErrFp, "Uso: remind [opcoes] arquivo [data] [hora] [*rep]\n"); fprintf(ErrFp, "Opcoes:\n"); fprintf(ErrFp, " -n Imprime a proxima ocorrencia em formato simples\n"); fprintf(ErrFp, " -r Desabilita a diretiva RUN\n"); fprintf(ErrFp, " -c[n] Produz calendario para n (default 1) meses\n"); fprintf(ErrFp, " -c+[n] Produz calendario para n (default 1) semanas\n"); fprintf(ErrFp, " -w[n[,p[,s]]] Especifica largura, preenchimento e espacejamento do calendario\n"); fprintf(ErrFp, " -s[+][n] Produz um `calendario simples' para n (1) meses (semanas)\n"); fprintf(ErrFp, " -p[n] Identico a -s, porem com saida compativel com rem2ps\n"); fprintf(ErrFp, " -v Modo verbose\n"); fprintf(ErrFp, " -o Ignora diretivas ONCE\n"); fprintf(ErrFp, " -t Aciona todos os compromissos futuros, sem considerar o delta\n"); fprintf(ErrFp, " -h Modo `Hush' - quieto\n"); #ifdef HAVE_QUEUED fprintf(ErrFp, " -a Nao aciona compromissos com hora imediatamente - apenas coloca na fila\n"); fprintf(ErrFp, " -q Nao coloca compromissos com hora na fila\n"); fprintf(ErrFp, " -f Aciona compromissos com hora em modo foreground\n"); fprintf(ErrFp, " -z[n] Modo `daemon', acordando a cada n (5) minutos.\n"); #endif fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trigger v=dumpvars l=showline\n"); fprintf(ErrFp, " -e Desvia mensagens normalmente enviadas a stderr para stdout\n"); fprintf(ErrFp, " -b[n] Formato da hora para o cal: 0=am/pm, 1=24hr, 2=nenhum\n"); fprintf(ErrFp, " -x[n] Limite de iteracoes para a clausula SATISFY (default=150)\n"); fprintf(ErrFp, " -kcmd Executa `cmd' para os compromissos com MSG\n"); fprintf(ErrFp, " -g[ddd] Classifica compromissos por data, hora e prioridade antes de exibir\n"); fprintf(ErrFp, " -ivar=val Inicializa (e preserva) variavel var com val\n"); fprintf(ErrFp, " -m Inicia o calendario na segunda, ao inves de domingo\n"); exit(1); } #endif /* L_IN_INIT */ remind-03.01.15/src/langs/romanian.h0000644000076400007640000001247712514120555015224 0ustar dfsdfs!/***************************************************************/ /* */ /* ROMANIAN.H */ /* */ /* Support for the Romanian language. */ /* */ /* Contributed by Liviu Daia */ /* */ /* This file is part of REMIND. */ /* */ /* REMIND is Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* This file is Copyright (C) 1996-1998 by Liviu Daia */ /* */ /***************************************************************/ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "Romanian" /* Day names */ #if ISOLATIN1 # define L_SUNDAY "Duminica" # define L_MONDAY "Luni" # define L_TUESDAY "Marti" # define L_WEDNESDAY "Miercuri" # define L_THURSDAY "Joi" # define L_FRIDAY "Vineri" # define L_SATURDAY "S\342mbata" #elif ISOLATIN2 # define L_SUNDAY "Duminic\343" # define L_MONDAY "Luni" # define L_TUESDAY "Mar\376i" # define L_WEDNESDAY "Miercuri" # define L_THURSDAY "Joi" # define L_FRIDAY "Vineri" # define L_SATURDAY "S\342mb\343t\343" #elif IBM852 # define L_SUNDAY "Duminic\307" # define L_MONDAY "Luni" # define L_TUESDAY "Mar\316i" # define L_WEDNESDAY "Miercuri" # define L_THURSDAY "Joi" # define L_FRIDAY "Vineri" # define L_SATURDAY "S\203mb\307t\307" #else # define L_SUNDAY "Duminica" # define L_MONDAY "Luni" # define L_TUESDAY "Marti" # define L_WEDNESDAY "Miercuri" # define L_THURSDAY "Joi" # define L_FRIDAY "Vineri" # define L_SATURDAY "Sambata" #endif /* Month names */ #define L_JAN "Ianuarie" #define L_FEB "Februarie" #define L_MAR "Martie" #define L_APR "Aprilie" #define L_MAY "Mai" #define L_JUN "Iunie" #define L_JUL "Iulie" #define L_AUG "August" #define L_SEP "Septembrie" #define L_OCT "Octombrie" #define L_NOV "Noiembrie" #define L_DEC "Decembrie" /* Today and tomorrow */ #if ISOLATIN1 # define L_TODAY "astazi" # define L_TOMORROW "m\342ine" #elif ISOLATIN2 # define L_TODAY "ast\343zi" # define L_TOMORROW "m\342ine" #elif IBM852 # define L_TODAY "ast\307zi" # define L_TOMORROW "m\203ine" #else # define L_TODAY "astazi" # define L_TOMORROW "maine" #endif /* The default banner */ #define L_BANNER "Reamintiri pentru %w, %d %m %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" #ifdef L_IN_DOSUBST /*** The following are only used in dosubst.c ***/ /* Ago and from now */ #define L_AGO "acum" #define L_FROMNOW "peste" /* "in %d days' time" */ #define L_INXDAYS "peste %d zile" /* "on" as in "on date..." */ #define L_ON "pe" /* Pluralizing - this is a problem for many languages and may require a more drastic fix */ #define L_PLURAL "le" /* Minutes, hours, at, etc */ #define L_NOW "acum" #define L_AT "la ora" #define L_MINUTE "minut" #define L_HOUR "or" #define L_IS "este" #define L_WAS "a fost" /* What to add to make "minute" plural */ #define L_MPLU "e" #if ISOLATIN2 /* What to add to make "hour" plural */ # define L_HPLU_OVER hplu = (hdiff == 1 ? "\343" : "e"); # define L_AND "\272i" #elif IBM852 /* What to add to make "hour" plural */ # define L_HPLU_OVER hplu = (hdiff == 1 ? "\307" : "e"); # define L_AND "\255i" #else /* What to add to make "hour" plural */ # define L_HPLU_OVER hplu = (hdiff == 1 ? "a" : "e"); # define L_AND "si" #endif /* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc. See the file dosubst.c for more info. */ #if ISOLATIN2 # define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<4) ? " noaptea" : " diminea\376a" : (hour > 17) ? " seara" : " dup\343-amiaza"; #elif IBM852 # define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<4) ? " noaptea" : " diminea\316a" : (hour > 17) ? " seara" : " dup\307-amiaza"; #else # define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<4) ? " noaptea" : " dimineata" : (hour > 17) ? " seara" : " dupa-amiaza"; #endif #define L_ORDINAL_OVERRIDE plu = ""; #define L_A_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d, MonthName[m], y); #define L_C_OVER sprintf(s, "%s", DayName[jul%7]); #define L_G_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, MonthName[m]); #define L_J_OVER sprintf(s, "%s, %s %d, %d", DayName[jul%7], MonthName[m], d, y); #define L_K_OVER sprintf(s, "%s, %s %d", DayName[jul%7], MonthName[m], d); #define L_S_OVER #define L_U_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d, MonthName[m], y); #define L_V_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, MonthName[m]); #define L_1_OVER \ if (tdiff == 0) \ sprintf(s, L_NOW); \ else if (hdiff == 0) \ sprintf(s, "%s %d %s%s", when, mdiff, L_MINUTE, mplu); \ else if (mdiff == 0) \ sprintf(s, "%s %d %s%s", when, hdiff, L_HOUR, hplu); \ else \ sprintf(s, "%s %d %s%s %s %d %s%s", when, hdiff, \ L_HOUR, hplu, L_AND, mdiff, L_MINUTE, mplu); #endif /* L_IN_DOSUBST */ remind-03.01.15/src/langs/spanish.h0000644000076400007640000000462712514120544015061 0ustar dfsdfs/***************************************************************/ /* */ /* SPANISH.H */ /* */ /* Support for the Spanish language. */ /* */ /* Author: Rafa Couto */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #define L_LANGNAME "Spanish" /* Nombres de los di'as de la semana */ #define L_SUNDAY "Domingo" #define L_MONDAY "Lunes" #define L_TUESDAY "Martes" #if ISOLATIN1 #define L_WEDNESDAY "Mi\351rcoles" #else #define L_WEDNESDAY "Miercoles" #endif #define L_THURSDAY "Jueves" #define L_FRIDAY "Viernes" #if ISOLATIN1 #define L_SATURDAY "S\341bado" #else #define L_SATURDAY "Sabado" #endif /* Nombres de los meses */ #define L_JAN "Enero" #define L_FEB "Febrero" #define L_MAR "Marzo" #define L_APR "Abril" #define L_MAY "Mayo" #define L_JUN "Junio" #define L_JUL "Julio" #define L_AUG "Agosto" #define L_SEP "Septiembre" #define L_OCT "Octubre" #define L_NOV "Noviembre" #define L_DEC "Diciembre" /* Hoy y man~ana */ #define L_TODAY "hoy" #if ISOLATIN1 #define L_TOMORROW "ma\361ana" #else #define L_TOMORROW "manana" #endif /* El titular habitual */ #define L_BANNER "Agenda para el %w, %d%s %m, %y%o:" /* "am" and "pm" */ #define L_AM "am" #define L_PM "pm" /*** The following are only used in dosubst.c ***/ #ifdef L_IN_DOSUBST /* Hace y desde hoy */ #define L_AGO "hace" #define L_FROMNOW "desde hoy" /* "dentro de %d di'as" */ #if ISOLATIN1 #define L_INXDAYS "dentro de %d d\355as" #define L_ON "el d\355a" #else #define L_INXDAYS "dentro de %d di'as" #define L_ON "el di'a" #endif /* "el di'a..." */ /* plurales */ #define L_PLURAL "s" /* Minutos, horas, a las, etc */ #define L_NOW "ahora" #define L_AT "a las" #define L_MINUTE "minuto" #define L_HOUR "hora" #define L_IS "es" #define L_WAS "fue" #define L_AND "y" #define L_HPLU "s" #define L_MPLU "s" #endif /* L_IN_DOSUBST */ remind-03.01.15/src/main.c0000644000076400007640000011420112514120540013211 0ustar dfsdfs/***************************************************************/ /* */ /* MAIN.C */ /* */ /* Main program loop, as well as miscellaneous conversion */ /* routines, etc. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2011 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_LOCALE_H #include #endif #include #ifdef TIME_WITH_SYS_TIME #include #include #else #if defined(HAVE_SYS_TIME_H) || defined (TIME_WITH_SYS_TIME) #include #else #include #endif #endif #include #include "types.h" #include "protos.h" #include "expr.h" #include "globals.h" #include "err.h" static void DoReminders(void); /* Whooo... the putchar/Putchar/PutChar macros are a mess... my apologies... */ #define Putchar(c) PutChar(c) /***************************************************************/ /***************************************************************/ /** **/ /** Main Program Loop **/ /** **/ /***************************************************************/ /***************************************************************/ int main(int argc, char *argv[]) { int pid; #ifdef HAVE_SETLOCALE setlocale(LC_ALL, ""); #endif /* The very first thing to do is to set up ErrFp to be stderr */ ErrFp = stderr; /* Set up global vars */ ArgC = argc; ArgV = (char const **) argv; InitRemind(argc, (char const **) argv); if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) { ProduceCalendar(); return 0; } /* Are we purging old reminders? Then just run through the loop once! */ if (PurgeMode) { DoReminders(); return 0; } /* Not doing a calendar. Do the regular remind loop */ ShouldCache = (Iterations > 1); while (Iterations--) { DoReminders(); if (DebugFlag & DB_DUMP_VARS) { DumpVarTable(); DumpSysVarByName(NULL); } if (!Hush) { if (DestroyOmitContexts()) Eprint("%s", ErrMsg[E_PUSH_NOPOP]); if (!Daemon && !NextMode && !NumTriggered && !NumQueued) { printf("%s\n", ErrMsg[E_NOREMINDERS]); } else if (!Daemon && !NextMode && !NumTriggered) { printf(ErrMsg[M_QUEUED], NumQueued); } } /* If there are sorted reminders, handle them */ if (SortByDate) IssueSortedReminders(); /* If there are any background reminders queued up, handle them */ if (NumQueued || Daemon) { if (DontFork) { HandleQueuedReminders(); return 0; } else { pid = fork(); if (pid == 0) { HandleQueuedReminders(); return 0; } if (pid == -1) { fprintf(ErrFp, "%s", ErrMsg[E_CANTFORK]); return 1; } } } if (Iterations) { ClearGlobalOmits(); DestroyOmitContexts(); DestroyVars(0); NumTriggered = 0; JulianToday++; } } return 0; } void PurgeEchoLine(char const *fmt, ...) { va_list argptr; va_start(argptr, fmt); if (PurgeFP != NULL) { (void) vfprintf(PurgeFP, fmt, argptr); } va_end(argptr); } /***************************************************************/ /* */ /* DoReminders */ /* */ /* The normal case - we're not doing a calendar. */ /* */ /***************************************************************/ static void DoReminders(void) { int r; Token tok; char const *s; Parser p; int purge_handled; if (!UseStdin) { FileAccessDate = GetAccessDate(InitialFile); } else { FileAccessDate = JulianToday; } if (FileAccessDate < 0) { fprintf(ErrFp, "%s: `%s'.\n", ErrMsg[E_CANTACCESS], InitialFile); exit(1); } r=IncludeFile(InitialFile); if (r) { fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING], InitialFile, ErrMsg[r]); exit(1); } while(1) { r = ReadLine(); if (r == E_EOF) return; if (r) { Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]); exit(1); } s = FindInitialToken(&tok, CurLine); /* Should we ignore it? */ if (NumIfs && tok.type != T_If && tok.type != T_Else && tok.type != T_EndIf && tok.type != T_IfTrig && ShouldIgnoreLine()) { /*** IGNORE THE LINE ***/ if (PurgeMode) { if (strncmp(CurLine, "#!P", 3)) { PurgeEchoLine("%s\n", CurLine); } } } else { purge_handled = 0; /* Create a parser to parse the line */ CreateParser(s, &p); switch(tok.type) { case T_Empty: case T_Comment: if (!strncmp(CurLine, "#!P", 3)) { purge_handled = 1; } break; case T_Rem: r=DoRem(&p); purge_handled = 1; break; case T_ErrMsg: r=DoErrMsg(&p); break; case T_If: r=DoIf(&p); break; case T_IfTrig: r=DoIfTrig(&p); break; case T_Else: r=DoElse(&p); break; case T_EndIf: r=DoEndif(&p); break; case T_Include: /* In purge mode, include closes file, so we need to echo it here! */ if (PurgeMode) { PurgeEchoLine("%s\n", CurLine); } r=DoInclude(&p); purge_handled = 1; break; case T_Exit: DoExit(&p); break; case T_Flush: r=DoFlush(&p); break; case T_Set: r=DoSet(&p); break; case T_Fset: r=DoFset(&p); break; case T_UnSet: r=DoUnset(&p); break; case T_Clr: r=DoClear(&p); break; case T_Debug: r=DoDebug(&p); break; case T_Dumpvars: r=DoDump(&p); break; case T_Banner: r=DoBanner(&p); break; case T_Omit: r=DoOmit(&p); if (r == E_PARSE_AS_REM) { DestroyParser(&p); CreateParser(s, &p); r=DoRem(&p); purge_handled = 1; } break; case T_Pop: r=PopOmitContext(&p); break; case T_Preserve: r=DoPreserve(&p); break; case T_Push: r=PushOmitContext(&p); break; case T_RemType: if (tok.val == RUN_TYPE) { r=DoRun(&p); } else { CreateParser(CurLine, &p); r=DoRem(&p); purge_handled = 1; } break; /* If we don't recognize the command, do a REM by default */ /* Note: Since the parser hasn't been used yet, we don't */ /* need to destroy it here. */ default: CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break; } if (r && (!Hush || r != E_RUN_DISABLED)) { Eprint("%s", ErrMsg[r]); } if (PurgeMode) { if (!purge_handled) { PurgeEchoLine("%s\n", CurLine); } else { if (r) { PurgeEchoLine("#!P! Could not parse next line: %s\n", ErrMsg[r]); PurgeEchoLine("%s\n", CurLine); } } } /* Destroy the parser - free up resources it may be tying up */ DestroyParser(&p); } } } /***************************************************************/ /* */ /* Julian */ /* */ /* Given day, month, year, return Julian date in days since */ /* 1 January 1990. */ /* */ /***************************************************************/ int Julian(int year, int month, int day) { int y1 = BASE-1, y2 = year-1; int y4 = (y2 / 4) - (y1 / 4); /* Correct for leap years */ int y100 = (y2 / 100) - (y1 / 100); /* Don't count multiples of 100... */ int y400 = (y2 / 400) - (y1 / 400); /* ... but do count multiples of 400 */ return 365 * (year-BASE) + y4 - y100 + y400 + MonthIndex[IsLeapYear(year)][month] + day - 1; } /***************************************************************/ /* */ /* FromJulian */ /* */ /* Convert a Julian date to year, month, day. */ /* */ /***************************************************************/ void FromJulian(int jul, int *y, int *m, int *d) { int try_yr = (jul / 365) + BASE; int try_mon = 0; int t; /* Inline code for speed... */ int y1 = BASE-1, y2 = try_yr-1; int y4 = (y2 / 4) - (y1 / 4); /* Correct for leap years */ int y100 = (y2 / 100) - (y1 / 100); /* Don't count multiples of 100... */ int y400 = (y2 / 400) - (y1 / 400); /* ... but do count multiples of 400 */ int try_jul= 365 * (try_yr-BASE) + y4 - y100 + y400; while (try_jul > jul) { try_yr--; try_jul -= DaysInYear(try_yr); } jul -= try_jul; t = DaysInMonth(try_mon, try_yr); while (jul >= t) { jul -= t; try_mon++; t = DaysInMonth(try_mon, try_yr); } *y = try_yr; *m = try_mon; *d = jul + 1; return; } /***************************************************************/ /* */ /* ParseChar */ /* */ /* Parse a character from a parse pointer. If peek is non- */ /* zero, then just peek ahead; don't advance pointer. */ /* */ /***************************************************************/ int ParseChar(ParsePtr p, int *err, int peek) { Value val; int r; *err = 0; if (p->tokenPushed && *p->tokenPushed) { if (peek) return *p->tokenPushed; else { r = *p->tokenPushed++; if (!r) { DBufFree(&p->pushedToken); p->tokenPushed = NULL; } return r; } } while(1) { if (p->isnested) { if (*(p->epos)) { if (peek) { return *(p->epos); } else { return *(p->epos++); } } free((void *) p->etext); /* End of substituted expression */ p->etext = NULL; p->epos = NULL; p->isnested = 0; } if (!*(p->pos)) { return 0; } if (*p->pos != BEG_OF_EXPR || !p->allownested) { if (peek) { return *(p->pos); } else { return *(p->pos++); } } p->expr_happened = 1; p->pos++; r = EvalExpr(&(p->pos), &val, p); if (r) { *err = r; DestroyParser(p); return 0; } if (*p->pos != END_OF_EXPR) { *err = E_MISS_END; DestroyParser(p); DestroyValue(val); return 0; } p->pos++; r = DoCoerce(STR_TYPE, &val); if (r) { *err = r; return 0; } p->etext = val.v.str; val.type = ERR_TYPE; /* So it's not accidentally destroyed! */ p->isnested = 1; p->epos = p->etext; } } /***************************************************************/ /* */ /* ParseNonSpaceChar */ /* */ /* Parse the next non-space character. */ /* */ /***************************************************************/ int ParseNonSpaceChar(ParsePtr p, int *err, int peek) { int ch; ch = ParseChar(p, err, 1); if (*err) return 0; while (isempty(ch)) { ParseChar(p, err, 0); /* Guaranteed to work */ ch = ParseChar(p, err, 1); if (*err) return 0; } if (!peek) ch = ParseChar(p, err, 0); /* Guaranteed to work */ return ch; } /***************************************************************/ /* */ /* ParseToken */ /* */ /* Parse a token delimited by whitespace. */ /* */ /***************************************************************/ int ParseToken(ParsePtr p, DynamicBuffer *dbuf) { int c, err; DBufFree(dbuf); c = ParseChar(p, &err, 0); if (err) return err; while (c && isempty(c)) { c = ParseChar(p, &err, 0); if (err) return err; } if (!c) return OK; while (c && !isempty(c)) { if (DBufPutc(dbuf, c) != OK) { DBufFree(dbuf); return E_NO_MEM; } c = ParseChar(p, &err, 0); if (err) { DBufFree(dbuf); return err; } } return OK; } /***************************************************************/ /* */ /* ParseIdentifier */ /* */ /* Parse a valid identifier - ie, alpha or underscore */ /* followed by alphanum. Return E_BAD_ID if identifier is */ /* invalid. */ /* */ /***************************************************************/ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf) { int c, err; DBufFree(dbuf); c = ParseChar(p, &err, 0); if (err) return err; while (c && isempty(c)) { c = ParseChar(p, &err, 0); if (err) return err; } if (!c) return E_EOLN; if (c != '$' && c != '_' && !isalpha(c)) return E_BAD_ID; if (DBufPutc(dbuf, c) != OK) { DBufFree(dbuf); return E_NO_MEM; } while (1) { c = ParseChar(p, &err, 1); if (err) { DBufFree(dbuf); return err; } if (c != '_' && !isalnum(c)) return OK; c = ParseChar(p, &err, 0); /* Guaranteed to work */ if (DBufPutc(dbuf, c) != OK) { DBufFree(dbuf); return E_NO_MEM; } } } /***************************************************************/ /* */ /* EvaluateExpr */ /* */ /* We are expecting an expression here. Evaluate it and */ /* return the value. */ /* */ /***************************************************************/ int EvaluateExpr(ParsePtr p, Value *v) { int bracketed = 0; int r; if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */ while (isempty(*p->pos)) (p->pos)++; if (!p->pos) return E_PARSE_ERR; /* Missing expression */ if (*p->pos == BEG_OF_EXPR) { (p->pos)++; bracketed = 1; } r = EvalExpr(&(p->pos), v, p); if (r) return r; if (bracketed) { if (*p->pos != END_OF_EXPR) return E_MISS_END; (p->pos)++; } return OK; } /***************************************************************/ /* */ /* Eprint - print an error message. */ /* */ /***************************************************************/ void Eprint(char const *fmt, ...) { va_list argptr; /* Check if more than one error msg. from this line */ if (!FreshLine && !ShowAllErrors) return; if (FreshLine && FileName) { FreshLine = 0; if (strcmp(FileName, "-")) (void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo); else (void) fprintf(ErrFp, "-stdin-(%d): ", LineNo); if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp); } else if (FileName) { fprintf(ErrFp, " "); } va_start(argptr, fmt); (void) vfprintf(ErrFp, fmt, argptr); (void) fputc('\n', ErrFp); va_end(argptr); return; } /***************************************************************/ /* */ /* OutputLine */ /* */ /* Output a line from memory buffer to a file pointer. This */ /* simply involves escaping newlines. */ /* */ /***************************************************************/ void OutputLine(FILE *fp) { char const *s = CurLine; char c = 0; while (*s) { if (*s == '\n') Putc('\\', fp); Putc(*s, fp); c = *s++; } if (c != '\n') Putc('\n', fp); } /***************************************************************/ /* */ /* CreateParser */ /* */ /* Create a parser given a string buffer */ /* */ /***************************************************************/ void CreateParser(char const *s, ParsePtr p) { p->text = s; p->pos = s; p->isnested = 0; p->epos = NULL; p->etext = NULL; p->allownested = 1; p->tokenPushed = NULL; p->expr_happened = 0; p->nonconst_expr = 0; DBufInit(&p->pushedToken); } /***************************************************************/ /* */ /* DestroyParser */ /* */ /* Destroy a parser, freeing up resources used. */ /* */ /***************************************************************/ void DestroyParser(ParsePtr p) { if (p->isnested && p->etext) { free((void *) p->etext); p->etext = NULL; p->isnested = 0; } DBufFree(&p->pushedToken); } /***************************************************************/ /* */ /* PushToken - one level of token pushback. This is */ /* on a per-parser basis. */ /* */ /***************************************************************/ int PushToken(char const *tok, ParsePtr p) { DBufFree(&p->pushedToken); if (DBufPuts(&p->pushedToken, tok) != OK || DBufPutc(&p->pushedToken, ' ') != OK) { DBufFree(&p->pushedToken); return E_NO_MEM; } p->tokenPushed = DBufValue(&p->pushedToken); return OK; } /***************************************************************/ /* */ /* SystemTime */ /* */ /* Return the system time in seconds past midnight */ /* */ /***************************************************************/ long SystemTime(int realtime) { time_t tloc; struct tm *t; if (!realtime && (SysTime != -1L)) return SysTime; (void) time(&tloc); t = localtime(&tloc); return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L + (long) t->tm_sec; } /***************************************************************/ /* */ /* SystemDate */ /* */ /* Obtains today's date. Returns Julian date or -1 for */ /* failure. (Failure happens if sys date is before BASE */ /* year.) */ /* */ /***************************************************************/ int SystemDate(int *y, int *m, int *d) { time_t tloc; struct tm *t; (void) time(&tloc); t = localtime(&tloc); *d = t->tm_mday; *m = t->tm_mon; *y = t->tm_year + 1900; return Julian(*y, *m, *d); } /***************************************************************/ /* */ /* DoIf - handle the IF command. */ /* */ /***************************************************************/ int DoIf(ParsePtr p) { Value v; int r; unsigned syndrome; if (NumIfs >= IF_NEST) return E_NESTED_IF; if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE; else { if ( (r = EvaluateExpr(p, &v)) ) { syndrome = IF_TRUE | BEFORE_ELSE; Eprint("%s", ErrMsg[r]); } else if ( (v.type != STR_TYPE && v.v.val) || (v.type == STR_TYPE && strcmp(v.v.str, "")) ) { syndrome = IF_TRUE | BEFORE_ELSE; } else { syndrome = IF_FALSE | BEFORE_ELSE; if (PurgeMode) { PurgeEchoLine("%s\n", "#!P: The next IF evaluated false..."); PurgeEchoLine("%s\n", "#!P: REM statements in IF block not checked for purging."); } } } NumIfs++; IfFlags &= ~(IF_MASK << (2*NumIfs - 2)); IfFlags |= syndrome << (2 * NumIfs - 2); if (ShouldIgnoreLine()) return OK; return VerifyEoln(p); } /***************************************************************/ /* */ /* DoElse - handle the ELSE command. */ /* */ /***************************************************************/ int DoElse(ParsePtr p) { unsigned syndrome; int was_ignoring = ShouldIgnoreLine(); if (!NumIfs) return E_ELSE_NO_IF; syndrome = IfFlags >> (2 * NumIfs - 2); if ((syndrome & IF_ELSE_MASK) == AFTER_ELSE) return E_ELSE_NO_IF; IfFlags |= AFTER_ELSE << (2 * NumIfs - 2); if (PurgeMode && ShouldIgnoreLine() && !was_ignoring) { PurgeEchoLine("%s\n", "#!P: The previous IF evaluated true."); PurgeEchoLine("%s\n", "#!P: REM statements in ELSE block not checked for purging"); } return VerifyEoln(p); } /***************************************************************/ /* */ /* DoEndif - handle the Endif command. */ /* */ /***************************************************************/ int DoEndif(ParsePtr p) { if (!NumIfs) return E_ENDIF_NO_IF; NumIfs--; return VerifyEoln(p); } /***************************************************************/ /* */ /* DoIfTrig */ /* */ /* Handle the IFTRIG command. */ /* */ /***************************************************************/ int DoIfTrig(ParsePtr p) { int r, err; unsigned syndrome; Trigger trig; TimeTrig tim; int jul; if (NumIfs >= IF_NEST) return E_NESTED_IF; if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE; else { if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r; if (trig.typ != NO_TYPE) return E_PARSE_ERR; jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1); if (r) syndrome = IF_TRUE | BEFORE_ELSE; else { if (ShouldTriggerReminder(&trig, &tim, jul, &err)) { syndrome = IF_TRUE | BEFORE_ELSE; } else { syndrome = IF_FALSE | BEFORE_ELSE; if (PurgeMode) { PurgeEchoLine("%s\n", "#!P: The next IFTRIG did not trigger."); PurgeEchoLine("%s\n", "#!P: REM statements in IFTRIG block not checked for purging."); } } } FreeTrig(&trig); } NumIfs++; IfFlags &= ~(IF_MASK << (2*NumIfs - 2)); IfFlags |= syndrome << (2 * NumIfs - 2); return OK; } /***************************************************************/ /* */ /* ShouldIgnoreLine - given the current state of the IF */ /* stack, should we ignore the current line? */ /* */ /***************************************************************/ int ShouldIgnoreLine(void) { register int i, syndrome; /* Algorithm - go from outer to inner, and if any should be ignored, then ignore the whole. */ for (i=0; i> (i*2)) & IF_MASK; if (syndrome == IF_TRUE+AFTER_ELSE || syndrome == IF_FALSE+BEFORE_ELSE) return 1; } return 0; } /***************************************************************/ /* */ /* VerifyEoln */ /* */ /* Verify that current line contains no more tokens. */ /* */ /***************************************************************/ int VerifyEoln(ParsePtr p) { int r; DynamicBuffer buf; DBufInit(&buf); if ( (r = ParseToken(p, &buf)) ) return r; if (*DBufValue(&buf) && (*DBufValue(&buf) != '#') && (*DBufValue(&buf) != ';')) { Eprint("%s: `%s'", ErrMsg[E_EXPECTING_EOL], DBufValue(&buf)); DBufFree(&buf); return E_EXTRANEOUS_TOKEN; } DBufFree(&buf); return OK; } /***************************************************************/ /* */ /* DoDebug */ /* */ /* Set the debug options under program control. */ /* */ /***************************************************************/ int DoDebug(ParsePtr p) { int err; int ch; int val=1; while(1) { ch = ParseChar(p, &err, 0); if (err) return err; switch(ch) { case '#': case ';': case 0: return OK; case ' ': case '\t': break; case '+': val = 1; break; case '-': val = 0; break; case 'e': case 'E': if (val) DebugFlag |= DB_ECHO_LINE; else DebugFlag &= ~DB_ECHO_LINE; break; case 'x': case 'X': if (val) DebugFlag |= DB_PRTEXPR; else DebugFlag &= ~DB_PRTEXPR; break; case 't': case 'T': if (val) DebugFlag |= DB_PRTTRIG; else DebugFlag &= ~DB_PRTTRIG; break; case 'v': case 'V': if (val) DebugFlag |= DB_DUMP_VARS; else DebugFlag &= ~DB_DUMP_VARS; break; case 'l': case 'L': if (val) DebugFlag |= DB_PRTLINE; else DebugFlag &= ~DB_PRTLINE; break; case 'f': case 'F': if (val) DebugFlag |= DB_TRACE_FILES; else DebugFlag &= ~DB_TRACE_FILES; break; } } } /***************************************************************/ /* */ /* DoBanner */ /* */ /* Set the banner to be printed just before the first */ /* reminder is issued. */ /* */ /***************************************************************/ int DoBanner(ParsePtr p) { int err; int c; DynamicBuffer buf; DBufInit(&buf); c = ParseChar(p, &err, 0); if (err) return err; while (isempty(c)) { c = ParseChar(p, &err, 0); if (err) return err; } if (!c) return E_EOLN; while(c) { if (DBufPutc(&buf, c) != OK) return E_NO_MEM; c = ParseChar(p, &err, 0); if (err) { DBufFree(&buf); return err; } } DBufFree(&Banner); err = DBufPuts(&Banner, DBufValue(&buf)); DBufFree(&buf); return err; } /***************************************************************/ /* */ /* DoRun */ /* */ /* Enable or disable the RUN command under program control */ /* */ /* */ /***************************************************************/ int DoRun(ParsePtr p) { int r; DynamicBuffer buf; DBufInit(&buf); if ( (r=ParseToken(p, &buf)) ) return r; /* Only allow RUN ON in top-level script */ if (! StrCmpi(DBufValue(&buf), "ON")) { if (TopLevel()) RunDisabled &= ~RUN_SCRIPT; } /* But allow RUN OFF anywhere */ else if (! StrCmpi(DBufValue(&buf), "OFF")) RunDisabled |= RUN_SCRIPT; else { DBufFree(&buf); return E_PARSE_ERR; } DBufFree(&buf); return VerifyEoln(p); } /***************************************************************/ /* */ /* DoFlush */ /* */ /* Flush stdout and stderr */ /* */ /***************************************************************/ int DoFlush(ParsePtr p) { fflush(stdout); fflush(stderr); return VerifyEoln(p); } /***************************************************************/ /* */ /* DoExit */ /* */ /* Handle the EXIT command. */ /* */ /***************************************************************/ void DoExit(ParsePtr p) { int r; Value v; if (PurgeMode) return; r = EvaluateExpr(p, &v); if (r || v.type != INT_TYPE) exit(99); exit(v.v.val); } /***************************************************************/ /* */ /* DoErrMsg */ /* */ /* Issue an error message under program control. */ /* */ /***************************************************************/ int DoErrMsg(ParsePtr p) { TimeTrig tt; Trigger t; int r; char const *s; DynamicBuffer buf; if (PurgeMode) return OK; DBufInit(&buf); t.typ = MSG_TYPE; tt.ttime = SystemTime(0) / 60; if ( (r=DoSubst(p, &buf, &t, &tt, JulianToday, NORMAL_MODE)) ) { return r; } s = DBufValue(&buf); while (isempty(*s)) s++; fprintf(ErrFp, "%s\n", s); DBufFree(&buf); return OK; } /***************************************************************/ /* */ /* CalcMinsFromUTC */ /* */ /* Attempt to calculate the minutes from UTC for a specific */ /* date. */ /* */ /***************************************************************/ /* The array FoldArray[2][7] contains sample years which begin on the specified weekday. For example, FoldArray[0][2] is a non-leapyear beginning on Wednesday, and FoldArray[1][5] is a leapyear beginning on Saturday. Used to fold back dates which are too high for the standard Unix representation. NOTE: This implies that you cannot set BASE > 2001!!!!! */ static int FoldArray[2][7] = { {2001, 2002, 2003, 2009, 2010, 2005, 2006}, {2024, 2008, 2020, 2004, 2016, 2000, 2012} }; int CalcMinsFromUTC(int jul, int tim, int *mins, int *isdst) { /* Convert jul and tim to an Unix tm struct */ int yr, mon, day; int tdiff; struct tm local, utc, *temp; time_t loc_t, utc_t; int isdst_tmp; FromJulian(jul, &yr, &mon, &day); /* If the year is greater than 2037, some Unix machines have problems. Fold it back to a "similar" year and trust that the UTC calculations are still valid... */ if (FoldYear && yr>2037) { jul = Julian(yr, 0, 1); yr = FoldArray[IsLeapYear(yr)][jul%7]; } local.tm_sec = 0; local.tm_min = tim % 60; local.tm_hour = tim / 60; local.tm_mday = day; local.tm_mon = mon; local.tm_year = yr-1900; local.tm_isdst = -1; /* We don't know whether or not dst is in effect */ /* Horrible contortions to get minutes from UTC portably */ loc_t = mktime(&local); if (loc_t == -1) return 1; isdst_tmp = local.tm_isdst; local.tm_isdst = 0; loc_t = mktime(&local); if (loc_t == -1) return 1; temp = gmtime(&loc_t); utc = *temp; utc.tm_isdst = 0; utc_t = mktime(&utc); if (utc_t == -1) return 1; /* Compute difference between local time and UTC in seconds. Be careful, since time_t might be unsigned. */ tdiff = (int) difftime(loc_t, utc_t); if (isdst_tmp) tdiff += 60*60; if (mins) *mins = (int)(tdiff / 60); if (isdst) *isdst = isdst_tmp; return 0; } /***************************************************************/ /* */ /* FillParagraph */ /* */ /* Write a string to standard output, formatting it as a */ /* paragraph according to the FirstIndent, FormWidth and */ /* SubsIndent variables. Spaces are gobbled. Double-spaces */ /* are inserted after '.', '?' and '!'. Newlines in the */ /* source are treated as paragraph breaks. */ /* */ /***************************************************************/ /* A macro safe ONLY if used with arg with no side effects! */ #define ISBLANK(c) (isspace(c) && (c) != '\n') void FillParagraph(char const *s) { int line = 0; int i, j; int doublespace = 1; int pendspace; int len; char const *t; int roomleft; if (!s || !*s) return; /* Skip leading spaces */ while(ISBLANK(*s)) s++; /* Start formatting */ while(1) { /* If it's a carriage return, output it and start new paragraph */ if (*s == '\n') { Putchar('\n'); s++; line = 0; while(ISBLANK(*s)) s++; continue; } if (!*s) { return; } /* Over here, we're at the beginning of a line. Emit the correct number of spaces */ j = line ? SubsIndent : FirstIndent; for (i=0; i= MINUTES_PER_DAY) { loctime -= MINUTES_PER_DAY; locdate++; } *utcdate = locdate; *utctime = loctime; } /***************************************************************/ /* */ /* UTCToLocal */ /* */ /* Convert a UTC date/time to a local date/time. */ /* */ /***************************************************************/ void UTCToLocal(int utcdate, int utctime, int *locdate, int *loctime) { int diff; int dummy; /* Hack -- not quite right when DST changes. */ if (!CalculateUTC || CalcMinsFromUTC(utcdate, utctime, &diff, &dummy)) diff=MinsFromUTC; utctime += diff; if (utctime < 0) { utctime += MINUTES_PER_DAY; utcdate--; } else if (utctime >= MINUTES_PER_DAY) { utctime -= MINUTES_PER_DAY; utcdate++; } *locdate = utcdate; *loctime = utctime; } /***************************************************************/ /* */ /* SigIntHandler */ /* */ /* For debugging purposes, when sent a SIGINT, we print the */ /* contents of the queue. This does NOT work when the -f */ /* command-line flag is supplied. */ /* */ /***************************************************************/ void SigIntHandler(int d) { signal(SIGINT, SigIntHandler); GotSigInt(); exit(0); } void AppendTag(DynamicBuffer *buf, char const *s) { if (*(DBufValue(buf))) { DBufPutc(buf, ','); } DBufPuts(buf, s); } void FreeTrig(Trigger *t) { DBufFree(&(t->tags)); } remind-03.01.15/src/md5.c0000644000076400007640000001747312555504777013016 0ustar dfsdfs/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * LIC: GPL * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include /* for memcpy() */ #include "md5.h" static void byteReverse(unsigned char *buf, unsigned longs); /* * Note: this code is harmless on little-endian machines. */ static void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) { uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } #ifndef ASM_MD5 /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(uint32 buf[4], uint32 const in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } #endif remind-03.01.15/src/md5.h0000644000076400007640000000131311057403122012757 0ustar dfsdfs#ifndef MD5_H #define MD5_H /* * LIC: GPL */ #include "config.h" #if SIZEOF_UNSIGNED_INT == 4 typedef unsigned int uint32; #elif SIZEOF_UNSIGNED_LONG == 4 typedef unsigned long uint32; #else # error Could not find a 32-bit integer type #endif struct MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; void MD5Init(struct MD5Context *context); void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len); void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Transform(uint32 buf[4], uint32 const in[16]); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ typedef struct MD5Context MD5_CTX; #endif /* !MD5_H */ remind-03.01.15/src/moon.c0000644000076400007640000005132412514120535013247 0ustar dfsdfs/***************************************************************/ /* */ /* MOON.C */ /* */ /* Calculations for figuring out moon phases. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" /* All of these routines were adapted from the program "moontool" by John Walker, February 1988. Here's the blurb from moontool: ... The information is generally accurate to within ten minutes. The algorithms used in this program to calculate the positions Sun and Moon as seen from the Earth are given in the book "Practical Astronomy With Your Calculator" by Peter Duffett-Smith, Second Edition, Cambridge University Press, 1981. Ignore the word "Calculator" in the title; this is an essential reference if you're interested in developing software which calculates planetary positions, orbits, eclipses, and the like. If you're interested in pursuing such programming, you should also obtain: "Astronomical Formulae for Calculators" by Jean Meeus, Third Edition, Willmann-Bell, 1985. A must-have. "Planetary Programs and Tables from -4000 to +2800" by Pierre Bretagnon and Jean-Louis Simon, Willmann-Bell, 1986. If you want the utmost (outside of JPL) accuracy for the planets, it's here. "Celestial BASIC" by Eric Burgess, Revised Edition, Sybex, 1985. Very cookbook oriented, and many of the algorithms are hard to dig out of the turgid BASIC code, but you'll probably want it anyway. Many of these references can be obtained from Willmann-Bell, P.O. Box 35025, Richmond, VA 23235, USA. Phone: (804) 320-7016. In addition to their own publications, they stock most of the standard references for mathematical and positional astronomy. This program was written by: John Walker Autodesk, Inc. 2320 Marinship Way Sausalito, CA 94965 (415) 332-2344 Ext. 829 Usenet: {sun!well}!acad!kelvin This program is in the public domain: "Do what thou wilt shall be the whole of the law". I'd appreciate receiving any bug fixes and/or enhancements, which I'll incorporate in future versions of the program. Please leave the original attribution information intact so that credit and blame may be properly apportioned. */ #include #include #include #include #include "types.h" #include "protos.h" #include "expr.h" #include "globals.h" #include "err.h" /* Function prototypes */ static long jdate (int y, int mon, int day); static double jtime (int y, int mon, int day, int hour, int min, int sec); static void jyear (double td, int *yy, int *mm, int *dd); static void jhms (double j, int *h, int *m, int *s); static double meanphase (double sdate, double phase, double *usek); static double truephase (double k, double phase); static double kepler (double m, double ecc); static double phase (double, double *, double *, double *, double *, double *, double *); /* Astronomical constants */ #define epoch 2444238.5 /* 1980 January 0.0 */ /* Constants defining the Sun's apparent orbit */ #define elonge 278.833540 /* Ecliptic longitude of the Sun at epoch 1980.0 */ #define elongp 282.596403 /* Ecliptic longitude of the Sun at perigee */ #define eccent 0.016718 /* Eccentricity of Earth's orbit */ #define sunsmax 1.495985e8 /* Semi-major axis of Earth's orbit, km */ #define sunangsiz 0.533128 /* Sun's angular size, degrees, at semi-major axis distance */ /* Elements of the Moon's orbit, epoch 1980.0 */ #define mmlong 64.975464 /* Moon's mean lonigitude at the epoch */ #define mmlongp 349.383063 /* Mean longitude of the perigee at the epoch */ #define mlnode 151.950429 /* Mean longitude of the node at the epoch */ #define minc 5.145396 /* Inclination of the Moon's orbit */ #define mecc 0.054900 /* Eccentricity of the Moon's orbit */ #define mangsiz 0.5181 /* Moon's angular size at distance a from Earth */ #define msmax 384401.0 /* Semi-major axis of Moon's orbit in km */ #define mparallax 0.9507 /* Parallax at distance a from Earth */ #define synmonth 29.53058868 /* Synodic month (new Moon to new Moon) */ #define lunatbase 2423436.0 /* Base date for E. W. Brown's numbered series of lunations (1923 January 16) */ /* Properties of the Earth */ #define earthrad 6378.16 /* Radius of Earth in kilometres */ #ifdef PI #undef PI #endif #define PI 3.14159265358979323846 /* Handy mathematical functions */ #ifdef sgn #undef sgn #endif #define sgn(x) (((x) < 0) ? -1 : ((x) > 0 ? 1 : 0)) /* Extract sign */ #ifdef abs #undef abs #endif #define abs(x) ((x) < 0 ? (-(x)) : (x)) /* Absolute val */ #define fixangle(a) ((a) - 360.0 * (floor((a) / 360.0))) /* Fix angle */ #define torad(d) ((d) * (PI / 180.0)) /* Deg->Rad */ #define todeg(d) ((d) * (180.0 / PI)) /* Rad->Deg */ #define dsin(x) (sin(torad((x)))) /* Sin from deg */ #define dcos(x) (cos(torad((x)))) /* Cos from deg */ /***************************************************************/ /* */ /* jdate */ /* */ /* Convert a date and time to Julian day and fraction. */ /* */ /***************************************************************/ static long jdate(int y, int mon, int day) { long c, m; m = mon+1; if (m>2) { m -= 3; } else { m += 9; y--; } c = y/100L; /* Century */ y -= 100L * c; return day + (c*146097L)/4 + (y*1461L)/4 + (m*153L+2)/5 + 1721119L; } /***************************************************************/ /* */ /* jtime */ /* */ /* Convert a GMT date and time to astronomical Julian time, */ /* i.e. Julian date plus day fraction, expressed as a double */ /* */ /***************************************************************/ static double jtime(int y, int mon, int day, int hour, int min, int sec) { return (jdate(y, mon, day)-0.5) + (sec + 60L * (long) min + 3600L * (long) hour) / 86400.0; } /***************************************************************/ /* */ /* jyear */ /* */ /* Convert a Julian date to year, month, day. */ /* */ /***************************************************************/ static void jyear(double td, int *yy, int *mm, int *dd) { double j, d, y, m; td += 0.5; /* Astronomical to civil */ j = floor(td); j = j - 1721119.0; y = floor(((4 * j) - 1) / 146097.0); j = (j * 4.0) - (1.0 + (146097.0 * y)); d = floor(j / 4.0); j = floor(((4.0 * d) + 3.0) / 1461.0); d = ((4.0 * d) + 3.0) - (1461.0 * j); d = floor((d + 4.0) / 4.0); m = floor(((5.0 * d) - 3) / 153.0); d = (5.0 * d) - (3.0 + (153.0 * m)); d = floor((d + 5.0) / 5.0); y = (100.0 * y) + j; if (m < 10.0) m = m + 2; else { m = m - 10; y = y + 1; } *yy = y; *mm = m; *dd = d; } /***************************************************************/ /* */ /* jhms */ /* */ /* Convert a Julian time to hour, minutes and seconds. */ /* */ /***************************************************************/ static void jhms(double j, int *h, int *m, int *s) { long ij; j += 0.5; /* Astronomical to civil */ ij = (j - floor(j)) * 86400.0; *h = ij / 3600L; *m = (ij / 60L) % 60L; *s = ij % 60L; } /***************************************************************/ /* */ /* meanphase */ /* */ /* Calculates mean phase of the Moon for a */ /* given base date and desired phase: */ /* 0.0 New Moon */ /* 0.25 First quarter */ /* 0.5 Full moon */ /* 0.75 Last quarter */ /* Beware!!! This routine returns meaningless */ /* results for any other phase arguments. Don't */ /* attempt to generalise it without understanding */ /* that the motion of the moon is far more complicated */ /* than this calculation reveals. */ /* */ /***************************************************************/ static double meanphase(double sdate, double phase, double *usek) { double k, t, t2, t3, nt1; /*** The following was the original code: It gave roundoff errors causing moonphase info to fail for Dec 1994. ***/ /* jyear(sdate, &yy, &mm, &dd); k = (yy + (mm/12.0) - 1900) * 12.368531; */ /*** The next line is the replacement ***/ k = (sdate - 2415020.0) / synmonth; /* Time in Julian centuries from 1900 January 0.5 */ t = (sdate - 2415020.0) / 36525.0; t2 = t * t; /* Square for frequent use */ t3 = t2 * t; /* Cube for frequent use */ *usek = k = floor(k) + phase; nt1 = 2415020.75933 + synmonth * k + 0.0001178 * t2 - 0.000000155 * t3 + 0.00033 * dsin(166.56 + 132.87 * t - 0.009173 * t2); return nt1; } /***************************************************************/ /* */ /* truephase */ /* */ /* Given a K value used to determine the */ /* mean phase of the new moon, and a phase */ /* selector (0.0, 0.25, 0.5, 0.75), obtain */ /* the true, corrected phase time. */ /* */ /***************************************************************/ static double truephase(double k, double phase) { double t, t2, t3, pt, m, mprime, f; int apcor = 0; k += phase; /* Add phase to new moon time */ t = k / 1236.8531; /* Time in Julian centuries from 1900 January 0.5 */ t2 = t * t; /* Square for frequent use */ t3 = t2 * t; /* Cube for frequent use */ pt = 2415020.75933 /* Mean time of phase */ + synmonth * k + 0.0001178 * t2 - 0.000000155 * t3 + 0.00033 * dsin(166.56 + 132.87 * t - 0.009173 * t2); m = 359.2242 /* Sun's mean anomaly */ + 29.10535608 * k - 0.0000333 * t2 - 0.00000347 * t3; mprime = 306.0253 /* Moon's mean anomaly */ + 385.81691806 * k + 0.0107306 * t2 + 0.00001236 * t3; f = 21.2964 /* Moon's argument of latitude */ + 390.67050646 * k - 0.0016528 * t2 - 0.00000239 * t3; if ((phase < 0.01) || (abs(phase - 0.5) < 0.01)) { /* Corrections for New and Full Moon */ pt += (0.1734 - 0.000393 * t) * dsin(m) + 0.0021 * dsin(2 * m) - 0.4068 * dsin(mprime) + 0.0161 * dsin(2 * mprime) - 0.0004 * dsin(3 * mprime) + 0.0104 * dsin(2 * f) - 0.0051 * dsin(m + mprime) - 0.0074 * dsin(m - mprime) + 0.0004 * dsin(2 * f + m) - 0.0004 * dsin(2 * f - m) - 0.0006 * dsin(2 * f + mprime) + 0.0010 * dsin(2 * f - mprime) + 0.0005 * dsin(m + 2 * mprime); apcor = 1; } else if ((abs(phase - 0.25) < 0.01 || (abs(phase - 0.75) < 0.01))) { pt += (0.1721 - 0.0004 * t) * dsin(m) + 0.0021 * dsin(2 * m) - 0.6280 * dsin(mprime) + 0.0089 * dsin(2 * mprime) - 0.0004 * dsin(3 * mprime) + 0.0079 * dsin(2 * f) - 0.0119 * dsin(m + mprime) - 0.0047 * dsin(m - mprime) + 0.0003 * dsin(2 * f + m) - 0.0004 * dsin(2 * f - m) - 0.0006 * dsin(2 * f + mprime) + 0.0021 * dsin(2 * f - mprime) + 0.0003 * dsin(m + 2 * mprime) + 0.0004 * dsin(m - 2 * mprime) - 0.0003 * dsin(2 * m + mprime); if (phase < 0.5) /* First quarter correction */ pt += 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime); else /* Last quarter correction */ pt += -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime); apcor = 1; } if (!apcor) return 0.0; return pt; } /***************************************************************/ /* */ /* kepler */ /* */ /* Solve the equation of Kepler. */ /* */ /***************************************************************/ static double kepler(double m, double ecc) { double e, delta; #define EPSILON 1E-6 e = m = torad(m); do { delta = e - ecc * sin(e) - m; e -= delta / (1 - ecc * cos(e)); } while (abs(delta) > EPSILON); return e; } /***************************************************************/ /* */ /* PHASE -- Calculate phase of moon as a fraction: */ /* */ /* The argument is the time for which the phase is */ /* Requested, expressed as a Julian date and */ /* fraction. Returns the terminator phase angle as a */ /* percentage of a full circle (i.e., 0 to 1), and */ /* stores into pointer arguments the illuminated */ /* fraction of the Moon's disc, the Moon's age in */ /* days and fraction, the distance of the Moon from */ /* the centre of the Earth, and the angular diameter */ /* subtended by the Moon as seen by an observer at */ /* the centre of the Earth. */ /* */ /***************************************************************/ static double phase(double pdate, double *pphase, double *mage, double *dist, double *angdia, double *sudist, double *suangdia) { double Day, N, M, Ec, Lambdasun, ml, MM, MN, Ev, Ae, A3, MmP, mEc, A4, lP, V, lPP, NP, y, x, Lambdamoon, MoonAge, MoonPhase, MoonDist, MoonDFrac, MoonAng, F, SunDist, SunAng; /* Calculation of the Sun's position */ Day = pdate - epoch; /* Date within epoch */ N = fixangle((360 / 365.2422) * Day); /* Mean anomaly of the Sun */ M = fixangle(N + elonge - elongp); /* Convert from perigee co-ordinates to epoch 1980.0 */ Ec = kepler(M, eccent); /* Solve equation of Kepler */ Ec = sqrt((1 + eccent) / (1 - eccent)) * tan(Ec / 2); Ec = 2 * todeg(atan(Ec)); /* 1 anomaly */ Lambdasun = fixangle(Ec + elongp); /* Sun's geocentric ecliptic longitude */ /* Orbital distance factor */ F = ((1 + eccent * cos(torad(Ec))) / (1 - eccent * eccent)); SunDist = sunsmax / F; /* Distance to Sun in km */ SunAng = F * sunangsiz; /* Sun's angular size in degrees */ /* Calculation of the Moon's position */ /* Moon's mean longitude */ ml = fixangle(13.1763966 * Day + mmlong); /* Moon's mean anomaly */ MM = fixangle(ml - 0.1114041 * Day - mmlongp); /* Moon's ascending node mean longitude */ MN = fixangle(mlnode - 0.0529539 * Day); /* Evection */ Ev = 1.2739 * sin(torad(2 * (ml - Lambdasun) - MM)); /* Annual equation */ Ae = 0.1858 * sin(torad(M)); /* Correction term */ A3 = 0.37 * sin(torad(M)); /* Corrected anomaly */ MmP = MM + Ev - Ae - A3; /* Correction for the equation of the centre */ mEc = 6.2886 * sin(torad(MmP)); /* Another correction term */ A4 = 0.214 * sin(torad(2 * MmP)); /* Corrected longitude */ lP = ml + Ev + mEc - Ae + A4; /* Variation */ V = 0.6583 * sin(torad(2 * (lP - Lambdasun))); /* 1 longitude */ lPP = lP + V; /* Corrected longitude of the node */ NP = MN - 0.16 * sin(torad(M)); /* Y inclination coordinate */ y = sin(torad(lPP - NP)) * cos(torad(minc)); /* X inclination coordinate */ x = cos(torad(lPP - NP)); /* Ecliptic longitude */ Lambdamoon = todeg(atan2(y, x)); Lambdamoon += NP; /* Calculation of the phase of the Moon */ /* Age of the Moon in degrees */ MoonAge = lPP - Lambdasun; /* Phase of the Moon */ MoonPhase = (1 - cos(torad(MoonAge))) / 2; /* Calculate distance of moon from the centre of the Earth */ MoonDist = (msmax * (1 - mecc * mecc)) / (1 + mecc * cos(torad(MmP + mEc))); /* Calculate Moon's angular diameter */ MoonDFrac = MoonDist / msmax; MoonAng = mangsiz / MoonDFrac; if(pphase) *pphase = MoonPhase; if(mage) *mage = synmonth * (fixangle(MoonAge) / 360.0); if(dist) *dist = MoonDist; if(angdia) *angdia = MoonAng; if(sudist) *sudist = SunDist; if(suangdia) *suangdia = SunAng; return fixangle(MoonAge) / 360.0; } /***************************************************************/ /* */ /* MoonPhase */ /* */ /* Interface routine dealing in Remind representations. */ /* Given a local date and time, returns the moon phase at */ /* that date and time as a number from 0 to 360. */ /* */ /***************************************************************/ int MoonPhase(int date, int time) { int utcd, utct; int y, m, d; double jd, mp; /* Convert from local to UTC */ LocalToUTC(date, time, &utcd, &utct); /* Convert from Remind representation to year/mon/day */ FromJulian(utcd, &y, &m, &d); /* Convert to a true Julian date -- sorry for the name clashes! */ jd = jtime(y, m, d, (utct / 60), (utct % 60), 0); /* Calculate moon phase */ mp = 360.0 * phase(jd, NULL, NULL, NULL, NULL, NULL, NULL); return (int) mp; } /***************************************************************/ /* */ /* HuntPhase */ /* */ /* Given a starting date and time and a target phase, find */ /* the first date on or after the starting date and time when */ /* the moon hits the specified phase. Phase must be from */ /* 0 to 3 for new, 1stq, full, 3rdq */ /* */ /***************************************************************/ void HuntPhase(int startdate, int starttim, int phas, int *date, int *time) { int utcd, utct; int y, m, d; int h, min, s; int d1, t1; double k1, k2, jd, jdorig; double nt1, nt2; /* Convert from local to UTC */ LocalToUTC(startdate, starttim, &utcd, &utct); /* Convert from Remind representation to year/mon/day */ FromJulian(utcd, &y, &m, &d); /* Convert to a true Julian date -- sorry for the name clashes! */ jdorig = jtime(y, m, d, (utct / 60), (utct % 60), 0); jd = jdorig - 45.0; nt1 = meanphase(jd, 0.0, &k1); while(1) { jd += synmonth; nt2 = meanphase(jd, 0.0, &k2); if (nt1 <= jdorig && nt2 > jdorig) break; nt1 = nt2; k1 = k2; } jd = truephase(k1, phas/4.0); if (jd < jdorig) jd = truephase(k2, phas/4.0); /* Convert back to Remind format */ jyear(jd, &y, &m, &d); jhms(jd, &h, &min, &s); d1 = Julian(y, m, d); t1 = h*60 + min; UTCToLocal(d1, t1, date, time); } remind-03.01.15/src/omit.c0000644000076400007640000003507312514120532013247 0ustar dfsdfs/***************************************************************/ /* */ /* OMIT.C */ /* */ /* This file handles all global OMIT commands, and maintains */ /* the data structures for OMITted dates. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include "types.h" #include "protos.h" #include "globals.h" #include "err.h" #include "expr.h" static int BexistsIntArray (int array[], int num, int key); static void InsertIntoSortedArray (int *array, int num, int key); /* Arrays for the global omits */ static int FullOmitArray[MAX_FULL_OMITS]; static int PartialOmitArray[MAX_PARTIAL_OMITS]; /* How many of each omit types do we have? */ static int NumFullOmits, NumPartialOmits; /* The structure for saving and restoring OMIT contexts */ typedef struct omitcontext { struct omitcontext *next; int numfull, numpart; int *fullsave; int *partsave; } OmitContext; /* The stack of saved omit contexts */ static OmitContext *SavedOmitContexts = NULL; /***************************************************************/ /* */ /* ClearGlobalOmits */ /* */ /* Clear all the global OMIT context. */ /* */ /***************************************************************/ int ClearGlobalOmits(void) { NumFullOmits = NumPartialOmits = 0; return OK; } /***************************************************************/ /* */ /* DoClear */ /* */ /* The command-line function CLEAR-OMIT-CONTEXT */ /* */ /***************************************************************/ int DoClear(ParsePtr p) { ClearGlobalOmits(); return VerifyEoln(p); } /***************************************************************/ /* */ /* DestroyOmitContexts */ /* */ /* Free all the memory used by saved OMIT contexts. */ /* As a side effect, return the number of OMIT contexts */ /* destroyed. */ /* */ /***************************************************************/ int DestroyOmitContexts(void) { OmitContext *c = SavedOmitContexts; OmitContext *d; int num = 0; while (c) { num++; if (c->fullsave) free(c->fullsave); if (c->partsave) free(c->partsave); d = c->next; free(c); c = d; } SavedOmitContexts = NULL; return num; } /***************************************************************/ /* */ /* PushOmitContext */ /* */ /* Push the OMIT context on to the stack. */ /* */ /***************************************************************/ int PushOmitContext(ParsePtr p) { register int i; OmitContext *context; /* Create the saved context */ context = NEW(OmitContext); if (!context) return E_NO_MEM; context->numfull = NumFullOmits; context->numpart = NumPartialOmits; context->fullsave = malloc(NumFullOmits * sizeof(int)); if (NumFullOmits && !context->fullsave) { free(context); return E_NO_MEM; } context->partsave = malloc(NumPartialOmits * sizeof(int)); if (NumPartialOmits && !context->partsave) { free(context->fullsave); free(context); return E_NO_MEM; } /* Copy the context over */ for (i=0; ifullsave + i) = FullOmitArray[i]; for (i=0; ipartsave + i) = PartialOmitArray[i]; /* Add the context to the stack */ context->next = SavedOmitContexts; SavedOmitContexts = context; return VerifyEoln(p); } /***************************************************************/ /* */ /* PopOmitContext */ /* */ /* Pop the OMIT context off of the stack. */ /* */ /***************************************************************/ int PopOmitContext(ParsePtr p) { register int i; OmitContext *c = SavedOmitContexts; if (!c) return E_POP_NO_PUSH; NumFullOmits = c->numfull; NumPartialOmits = c->numpart; /* Copy the context over */ for (i=0; ifullsave + i); for (i=0; ipartsave + i); /* Remove the context from the stack */ SavedOmitContexts = c->next; /* Free memory used by the saved context */ if (c->partsave) free(c->partsave); if (c->fullsave) free(c->fullsave); free(c); return VerifyEoln(p); } /***************************************************************/ /* */ /* IsOmitted */ /* */ /* Set *omit to non-zero if date is omitted, else 0. Returns */ /* OK or an error code. */ /* */ /***************************************************************/ int IsOmitted(int jul, int localomit, char const *omitfunc, int *omit) { int y, m, d; /* If we have an omitfunc, we *only* use it and ignore local/global OMITs */ if (omitfunc && *omitfunc && UserFuncExists(omitfunc)) { char expr[VAR_NAME_LEN + 32]; char const *s; int r; Value v; FromJulian(jul, &y, &m, &d); sprintf(expr, "%s('%04d-%02d-%02d')", omitfunc, y, m+1, d); s = expr; r = EvalExpr(&s, &v, NULL); if (r) return r; if (v.type == INT_TYPE && v.v.val != 0) { *omit = 1; } else { *omit = 0; } return OK; } /* Is it omitted because of local omits? */ if (localomit & (1 << (jul % 7))) { *omit = 1; return OK; } /* Is it omitted because of fully-specified omits? */ if (BexistsIntArray(FullOmitArray, NumFullOmits, jul)) { *omit = 1; return OK; } FromJulian(jul, &y, &m, &d); if (BexistsIntArray(PartialOmitArray, NumPartialOmits, (m << 5) + d)) { *omit = 1; return OK; } /* Not omitted */ *omit = 0; return OK; } /***************************************************************/ /* */ /* BexistsIntArray */ /* */ /* Perform a binary search on an integer array. Return 1 if */ /* element is found, 0 otherwise. */ /* */ /***************************************************************/ static int BexistsIntArray(int array[], int num, int key) { int top=num-1, bot=0, mid; while (top >= bot) { mid = (top+bot)/2; if (array[mid] == key) return 1; else if (array[mid] > key) top = mid-1; else bot=mid+1; } return 0; } /***************************************************************/ /* */ /* InsertIntoSortedArray */ /* */ /* Insert a key into a sorted array. We assume that there is */ /* room in the array for it. */ /* */ /***************************************************************/ static void InsertIntoSortedArray(int *array, int num, int key) { /* num is number of elements CURRENTLY in the array. */ int *cur = array+num; while (cur > array && *(cur-1) > key) { *cur = *(cur-1); cur--; } *cur = key; } static int DoThroughOmit(ParsePtr p, int y, int m, int d); static void DumpOmits(void); /***************************************************************/ /* */ /* DoOmit */ /* */ /* Do a global OMIT command. */ /* */ /***************************************************************/ int DoOmit(ParsePtr p) { int y = NO_YR, m = NO_MON, d = NO_DAY, r; Token tok; int parsing=1; int syndrome; int not_first_token = -1; DynamicBuffer buf; DBufInit(&buf); /* Parse the OMIT. We need a month and day; year is optional. */ while(parsing) { not_first_token++; if ( (r=ParseToken(p, &buf)) ) return r; FindToken(DBufValue(&buf), &tok); switch (tok.type) { case T_Dumpvars: if (not_first_token) return E_PARSE_ERR; DBufFree(&buf); r = VerifyEoln(p); if (r != OK) return r; DumpOmits(); return OK; case T_Date: DBufFree(&buf); if (y != NO_YR) return E_YR_TWICE; if (m != NO_MON) return E_MON_TWICE; if (d != NO_DAY) return E_DAY_TWICE; FromJulian(tok.val, &y, &m, &d); break; case T_Year: DBufFree(&buf); if (y != NO_YR) return E_YR_TWICE; y = tok.val; break; case T_Month: DBufFree(&buf); if (m != NO_MON) return E_MON_TWICE; m = tok.val; break; case T_Day: DBufFree(&buf); if (d != NO_DAY) return E_DAY_TWICE; d = tok.val; break; case T_Delta: DBufFree(&buf); break; case T_Through: DBufFree(&buf); if (y == NO_YR || m == NO_MON || d == NO_DAY) return E_INCOMPLETE; return DoThroughOmit(p, y, m, d); case T_Empty: case T_Comment: case T_RemType: case T_Priority: case T_Tag: case T_Duration: DBufFree(&buf); parsing = 0; break; default: Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN], DBufValue(&buf)); DBufFree(&buf); return E_UNKNOWN_TOKEN; } } if (m == NO_MON || d == NO_DAY) return E_SPEC_MON_DAY; if (y == NO_YR) { if (NumPartialOmits == MAX_PARTIAL_OMITS) return E_2MANY_PART; if (d > MonthDays[m]) return E_BAD_DATE; syndrome = (m<<5) + d; if (!BexistsIntArray(PartialOmitArray, NumPartialOmits, syndrome)) { InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome); NumPartialOmits++; } } else { if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL; if (d > DaysInMonth(m, y)) return E_BAD_DATE; syndrome = Julian(y, m, d); if (!BexistsIntArray(FullOmitArray, NumFullOmits, syndrome)) { InsertIntoSortedArray(FullOmitArray, NumFullOmits, syndrome); NumFullOmits++; } } if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM; return OK; } static int DoThroughOmit(ParsePtr p, int ystart, int mstart, int dstart) { int yend = NO_YR, mend = NO_MON, dend = NO_DAY, r; int start, end, tmp; int parsing = 1; Token tok; DynamicBuffer buf; DBufInit(&buf); while(parsing) { if ( (r=ParseToken(p, &buf)) ) return r; FindToken(DBufValue(&buf), &tok); switch(tok.type) { case T_Date: DBufFree(&buf); if (yend != NO_YR) return E_YR_TWICE; if (mend != NO_MON) return E_MON_TWICE; if (dend != NO_DAY) return E_DAY_TWICE; FromJulian(tok.val, ¥d, &mend, &dend); break; case T_Year: DBufFree(&buf); if (yend != NO_YR) return E_YR_TWICE; yend = tok.val; break; case T_Month: DBufFree(&buf); if (mend != NO_MON) return E_MON_TWICE; mend = tok.val; break; case T_Day: DBufFree(&buf); if (dend != NO_DAY) return E_DAY_TWICE; dend = tok.val; break; case T_Empty: case T_Comment: case T_RemType: case T_Priority: case T_Tag: case T_Duration: DBufFree(&buf); parsing = 0; break; default: Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN], DBufValue(&buf)); DBufFree(&buf); return E_UNKNOWN_TOKEN; } } if (yend == NO_YR || mend == NO_MON || dend == NO_DAY) return E_INCOMPLETE; if (dend > DaysInMonth(mend, yend)) return E_BAD_DATE; if (dstart > DaysInMonth(mstart, ystart)) return E_BAD_DATE; start = Julian(ystart, mstart, dstart); end = Julian(yend, mend, dend); if (end < start) { tmp = start; start = end; end = tmp; } tmp = end - start + 1; /* Don't create any OMITs if there would be too many. */ if (NumFullOmits + tmp >= MAX_FULL_OMITS) return E_2MANY_FULL; for (tmp = start; tmp <= end; tmp++) { if (!BexistsIntArray(FullOmitArray, NumFullOmits, tmp)) { InsertIntoSortedArray(FullOmitArray, NumFullOmits, tmp); NumFullOmits++; } } if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM; return OK; } void DumpOmits(void) { int i; int y, m, d; printf("Global Full OMITs (%d of maximum allowed %d):\n", NumFullOmits, MAX_FULL_OMITS); if (!NumFullOmits) { printf("\tNone.\n"); } else { for (i=0; i> 5 & 0xf; d = PartialOmitArray[i] & 0x1f; printf("\t%02d%c%02d\n", m+1, DateSep, d); } } } remind-03.01.15/src/protos.h0000644000076400007640000001425112514120526013630 0ustar dfsdfs/***************************************************************/ /* */ /* PROTOS.H */ /* */ /* Function Prototypes. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ /* Define a string assignment macro - be careful!!! */ #define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); } /* Define a general malloc routine for creating pointers to objects */ #define NEW(type) (malloc(sizeof(type))) /* Characters to ignore */ #define isempty(c) (isspace(c) || ((c) == '\\')) #include "dynbuf.h" int CallUserFunc (char const *name, int nargs, ParsePtr p); int DoFset (ParsePtr p); void ProduceCalendar (void); char const *SimpleTime (int tim); char const *CalendarTime (int tim, int duration); int DoRem (ParsePtr p); int DoFlush (ParsePtr p); void DoExit (ParsePtr p); int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals); int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int jul); int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int jul, int *err); int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul, int mode); int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int jul, int tim); int ParseLiteralDate (char const **s, int *jul, int *tim); int EvalExpr (char const **e, Value *v, ParsePtr p); int DoCoerce (char type, Value *v); void PrintValue (Value *v, FILE *fp); int CopyValue (Value *dest, const Value *src); int ReadLine (void); int OpenFile (char const *fname); int DoInclude (ParsePtr p); int IncludeFile (char const *fname); int GetAccessDate (char const *file); int SetAccessDate (char const *fname, int jul); int TopLevel (void); int CallFunc (BuiltinFunc *f, int nargs); void InitRemind (int argc, char const *argv[]); void Usage (void); int Julian (int year, int month, int day); void FromJulian (int jul, int *y, int *m, int *d); int ParseChar (ParsePtr p, int *err, int peek); int ParseToken (ParsePtr p, DynamicBuffer *dbuf); int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf); int EvaluateExpr (ParsePtr p, Value *v); int Evaluate (char const **s, Var *locals, ParsePtr p); int FnPopValStack (Value *val); void Eprint (char const *fmt, ...); void OutputLine (FILE *fp); void CreateParser (char const *s, ParsePtr p); void DestroyParser (ParsePtr p); int PushToken (char const *tok, ParsePtr p); long SystemTime (int realtime); int SystemDate (int *y, int *m, int *d); int DoIf (ParsePtr p); int DoElse (ParsePtr p); int DoEndif (ParsePtr p); int DoIfTrig (ParsePtr p); int ShouldIgnoreLine (void); int VerifyEoln (ParsePtr p); int DoDebug (ParsePtr p); int DoBanner (ParsePtr p); int DoRun (ParsePtr p); int DoErrMsg (ParsePtr p); int ClearGlobalOmits (void); int DoClear (ParsePtr p); int DestroyOmitContexts (void); int PushOmitContext (ParsePtr p); int PopOmitContext (ParsePtr p); int IsOmitted (int jul, int localomit, char const *omitfunc, int *omit); int DoOmit (ParsePtr p); int QueueReminder (ParsePtr p, Trigger *trig, TimeTrig *tim, char const *sched); void HandleQueuedReminders (void); char const *FindInitialToken (Token *tok, char const *s); void FindToken (char const *s, Token *tok); void FindNumericToken (char const *s, Token *t); int ComputeTrigger (int today, Trigger *trig, int *err, int save_in_globals); char *StrnCpy (char *dest, char const *source, int n); int StrMatch (char const *s1, char const *s2, int n); int StrinCmp (char const *s1, char const *s2, int n); char *StrDup (char const *s); int StrCmpi (char const *s1, char const *s2); Var *FindVar (char const *str, int create); int DeleteVar (char const *str); int SetVar (char const *str, Value *val); int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p); int DoSet (Parser *p); int DoUnset (Parser *p); int DoDump (ParsePtr p); void DumpVarTable (void); void DestroyVars (int all); int PreserveVar (char const *name); int DoPreserve (Parser *p); int DoSatRemind (Trigger *trig, TimeTrig *tim, ParsePtr p); int DoMsgCommand (char const *cmd, char const *msg); int ParseNonSpaceChar (ParsePtr p, int *err, int peek); unsigned int HashVal (char const *str); int DateOK (int y, int m, int d); Operator *FindOperator (char const *name, Operator where[], int num); BuiltinFunc *FindFunc (char const *name, BuiltinFunc where[], int num); int InsertIntoSortBuffer (int jul, int tim, char const *body, int typ, int prio); void IssueSortedReminders (void); int UserFuncExists (char const *fn); void JulToHeb (int jul, int *hy, int *hm, int *hd); int HebNameToNum (char const *mname); char const *HebMonthName (int m, int y); int RoshHashana (int i); long DaysToHebYear (int y); int DaysInHebYear (int y); char const *DaysInHebMonths (int ylen); int HebToJul (int hy, int hm, int hd); int GetValidHebDate (int yin, int min, int din, int adarbehave, int *mout, int *dout, int yahr); int GetNextHebrewDate (int julstart, int hm, int hd, int yahr, int adarbehave, int *ans); int ComputeJahr (int y, int m, int d, int *ans); int GetSysVar (char const *name, Value *val); int SetSysVar (char const *name, Value *val); void DumpSysVarByName (char const *name); int CalcMinsFromUTC (int jul, int tim, int *mins, int *isdst); void FillParagraph (char const *s); void LocalToUTC (int locdate, int loctime, int *utcdate, int *utctime); void UTCToLocal (int utcdate, int utctime, int *locdate, int *loctime); int MoonPhase (int date, int time); void HuntPhase (int startdate, int starttim, int phas, int *date, int *time); int CompareRems (int dat1, int tim1, int prio1, int dat2, int tim2, int prio2, int bydate, int bytime, int byprio, int untimed_first); void SigIntHandler (int d); void GotSigInt (void); void PurgeEchoLine(char const *fmt, ...); void FreeTrig(Trigger *t); void AppendTag(DynamicBuffer *buf, char const *s); char const *SynthesizeTag(void); remind-03.01.15/src/queue.c0000644000076400007640000003754512514120523013431 0ustar dfsdfs/***************************************************************/ /* */ /* QUEUE.C */ /* */ /* Queue up reminders for subsequent execution. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" /* Solaris needs this to get select() prototype */ #ifdef __sun__ #define __EXTENSIONS__ 1 #endif /* We only want object code generated if we have queued reminders */ #include #include #include #include #include #include #include #include #include #include "globals.h" #include "err.h" #include "types.h" #include "protos.h" #include "expr.h" /* List structure for holding queued reminders */ typedef struct queuedrem { struct queuedrem *next; int typ; int RunDisabled; int ntrig; char const *text; char passthru[PASSTHRU_LEN+1]; char sched[VAR_NAME_LEN+1]; DynamicBuffer tags; TimeTrig tt; } QueuedRem; /* Global variables */ static QueuedRem *QueueHead; static time_t FileModTime; static struct stat StatBuf; static void CheckInitialFile (void); static int CalculateNextTime (QueuedRem *q); static QueuedRem *FindNextReminder (void); static int CalculateNextTimeUsingSched (QueuedRem *q); static void DaemonWait (unsigned int sleeptime); static void reread (void); /***************************************************************/ /* */ /* QueueReminder */ /* */ /* Put the reminder on a queue for later, if queueing is */ /* enabled. */ /* */ /***************************************************************/ int QueueReminder(ParsePtr p, Trigger *trig, TimeTrig *tim, char const *sched) { QueuedRem *qelem; if (DontQueue || tim->ttime == NO_TIME || trig->typ == CAL_TYPE || tim->ttime < SystemTime(0) / 60 || ((trig->typ == RUN_TYPE) && RunDisabled)) return OK; qelem = NEW(QueuedRem); if (!qelem) { return E_NO_MEM; } qelem->text = StrDup(p->pos); /* Guaranteed that parser is not nested. */ if (!qelem->text) { free(qelem); return E_NO_MEM; } NumQueued++; qelem->typ = trig->typ; strcpy(qelem->passthru, trig->passthru); qelem->tt = *tim; qelem->next = QueueHead; qelem->RunDisabled = RunDisabled; qelem->ntrig = 0; strcpy(qelem->sched, sched); DBufInit(&(qelem->tags)); DBufPuts(&(qelem->tags), DBufValue(&(trig->tags))); if (SynthesizeTags) { AppendTag(&(qelem->tags), SynthesizeTag()); } QueueHead = qelem; return OK; } /***************************************************************/ /* */ /* HandleQueuedReminders */ /* */ /* Handle the issuing of queued reminders in the background */ /* */ /***************************************************************/ void HandleQueuedReminders(void) { QueuedRem *q = QueueHead; int TimeToSleep; unsigned SleepTime; Parser p; Trigger trig; /* Suppress the BANNER from being issued */ NumTriggered = 1; /* Turn off sorting -- otherwise, TriggerReminder has no effect! */ SortByDate = 0; /* If we are not connected to a tty, then we must close the * standard file descriptors. This is to prevent someone * doing: * remind file | | >log * and have hung because the child (us) is still * connected to it. This means the only commands that will be * processed correctly are RUN commands, provided they mail * the result back or use their own resource (as a window). */ if (!DontFork && (!isatty(1) || !isatty(2))) { close(1); close(2); } /* If we're a daemon, get the mod time of initial file */ if (Daemon > 0) { if (stat(InitialFile, &StatBuf)) { fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n", InitialFile); Daemon = 0; } else FileModTime = StatBuf.st_mtime; } /* Initialize the queue - initialize all the entries time of issue */ while (q) { q->tt.nexttime = (int) (SystemTime(0)/60 - 1); q->tt.nexttime = CalculateNextTime(q); q = q->next; } if (!DontFork || Daemon) signal(SIGINT, SigIntHandler); /* Sit in a loop, issuing reminders when necessary */ while(1) { q = FindNextReminder(); /* If no more reminders to issue, we're done unless we're a daemon. */ if (!q && !Daemon) break; if (Daemon && !q) { if (Daemon < 0) { /* Sleep until midnight */ TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(0); } else { TimeToSleep = 60*Daemon; } } else { TimeToSleep = q->tt.nexttime * 60L - SystemTime(0); } while (TimeToSleep > 0L) { SleepTime = TimeToSleep; if (Daemon > 0 && SleepTime > 60*Daemon) SleepTime = 60*Daemon; /* Wake up once a minute to recalibrate sleep time in case of laptop hibernation */ if (Daemon <= 0) { if (SleepTime > 60) { SleepTime = 60; } } if (Daemon >= 0) { sleep(SleepTime); } else { DaemonWait(SleepTime); } /* If not in daemon mode and day has rolled around, exit -- not much we can do. */ if (!Daemon) { int y, m, d; if (RealToday != SystemDate(&y, &m, &d)) { exit(0); } } if (Daemon > 0 && SleepTime) CheckInitialFile(); if (Daemon && !q) { if (Daemon < 0) { /* Sleep until midnight */ TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(0); } else { TimeToSleep = 60*Daemon; } } else { TimeToSleep = q->tt.nexttime * 60L - SystemTime(0); } } /* Do NOT trigger the reminder if tt.nexttime is more than a minute in the past. This can happen if the clock is changed or a laptop awakes from hibernation. However, DO triger if tt.nexttime == tt.ttime so all queued reminders are triggered at least once. */ if ((SystemTime(0) - (q->tt.nexttime * 60) <= 60) || (q->tt.nexttime == q->tt.ttime)) { /* Trigger the reminder */ CreateParser(q->text, &p); trig.typ = q->typ; strcpy(trig.passthru, q->passthru); RunDisabled = q->RunDisabled; if (Daemon < 0) { printf("NOTE reminder %s", SimpleTime(q->tt.ttime)); printf("%s", SimpleTime(SystemTime(0)/60)); if (!*DBufValue(&q->tags)) { printf("*\n"); } else { printf("%s\n", DBufValue(&(q->tags))); } } /* Set up global variables so some functions like trigdate() and trigtime() work correctly */ LastTriggerDate = JulianToday; LastTriggerTime = q->tt.ttime; LastTrigValid = 1; (void) TriggerReminder(&p, &trig, &q->tt, JulianToday); if (Daemon < 0) { printf("NOTE endreminder\n"); } fflush(stdout); DestroyParser(&p); } /* Calculate the next trigger time */ q->tt.nexttime = CalculateNextTime(q); } exit(0); } /***************************************************************/ /* */ /* CalculateNextTime */ /* */ /* Calculate the next time when a reminder should be issued. */ /* Return NO_TIME if reminder expired. */ /* Strategy is: If a sched() function is defined, call it. */ /* Otherwise, use AT time with delta and rep. If sched() */ /* fails, revert to AT with delta and rep. */ /* */ /***************************************************************/ static int CalculateNextTime(QueuedRem *q) { int tim = q->tt.ttime; int rep = q->tt.rep; int delta = q->tt.delta; int curtime = q->tt.nexttime+1; int r; /* Increment number of times this one has been triggered */ q->ntrig++; if (q->sched[0]) { r = CalculateNextTimeUsingSched(q); if (r != NO_TIME) return r; } if (delta == NO_DELTA) { if (tim < curtime) { return NO_TIME; } else { return tim; } } tim -= delta; if (rep == NO_REP) rep = delta; if (tim < curtime) tim += ((curtime - tim) / rep) * rep; if (tim < curtime) tim += rep; if (tim > q->tt.ttime) tim = q->tt.ttime; if (tim < curtime) return NO_TIME; else return tim; } /***************************************************************/ /* */ /* FindNextReminder */ /* */ /* Find the next reminder to trigger */ /* */ /***************************************************************/ static QueuedRem *FindNextReminder(void) { QueuedRem *q = QueueHead; QueuedRem *ans = NULL; while (q) { if (q->tt.nexttime != NO_TIME) { if (!ans) ans = q; else if (q->tt.nexttime < ans->tt.nexttime) ans = q; } q = q->next; } return ans; } /***************************************************************/ /* */ /* GotSigInt */ /* */ /* Split out what's done on a SIGINT from the SIGINT Handler. */ /* This will be necessary for OS/2 multithreaded. */ /* */ /***************************************************************/ void GotSigInt(void) { QueuedRem *q = QueueHead; printf("Contents of AT queue:%s", NL); while (q) { if (q->tt.nexttime != NO_TIME) { printf("Trigger: %02d%c%02d Activate: %02d%c%02d Rep: %d Delta: %d Sched: %s", q->tt.ttime / 60, TimeSep, q->tt.ttime % 60, q->tt.nexttime / 60, TimeSep, q->tt.nexttime % 60, q->tt.rep, q->tt.delta, q->sched); if (*q->sched) printf("(%d)", q->ntrig+1); printf("%s", NL); printf("Text: %s %s%s%s%s%s", ((q->typ == MSG_TYPE) ? "MSG" : ((q->typ == MSF_TYPE) ? "MSF" : ((q->typ == RUN_TYPE) ? "RUN" : "SPECIAL"))), q->passthru, (*(q->passthru)) ? " " : "", q->text, NL, NL); } q = q->next; } printf(NL); } /***************************************************************/ /* */ /* CheckInitialFile */ /* */ /* If the initial file has been modified, then restart the */ /* daemon. */ /* */ /***************************************************************/ static void CheckInitialFile(void) { /* If date has rolled around, or file has changed, spawn a new version. */ time_t tim = FileModTime; int y, m, d; if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime; if (tim != FileModTime || RealToday != SystemDate(&y, &m, &d)) { reread(); } } /***************************************************************/ /* */ /* CalculateNextTimeUsingSched */ /* */ /* Call the scheduling function. */ /* */ /***************************************************************/ static int CalculateNextTimeUsingSched(QueuedRem *q) { /* Use LineBuffer for temp. string storage. */ int r; Value v; char const *s; int LastTime = -1; int ThisTime; if (UserFuncExists(q->sched) != 1) { q->sched[0] = 0; return NO_TIME; } RunDisabled = q->RunDisabled; /* Don't want weird scheduling functions to be a security hole! */ while(1) { char exprBuf[VAR_NAME_LEN+32]; sprintf(exprBuf, "%s(%d)", q->sched, q->ntrig); s = exprBuf; r = EvalExpr(&s, &v, NULL); if (r) { q->sched[0] = 0; return NO_TIME; } if (v.type == TIME_TYPE) { ThisTime = v.v.val; } else if (v.type == INT_TYPE) { if (v.v.val > 0) if (LastTime >= 0) { ThisTime = LastTime + v.v.val; } else { ThisTime = q->tt.nexttime + v.v.val; } else ThisTime = q->tt.ttime + v.v.val; } else { DestroyValue(v); q->sched[0] = 0; return NO_TIME; } if (ThisTime < 0) ThisTime = 0; /* Can't be less than 00:00 */ if (ThisTime > (MINUTES_PER_DAY-1)) ThisTime = (MINUTES_PER_DAY-1); /* or greater than 11:59 */ if (DebugFlag & DB_PRTEXPR) { fprintf(ErrFp, "SCHED: Considering %02d%c%02d\n", ThisTime / 60, TimeSep, ThisTime % 60); } if (ThisTime > q->tt.nexttime) return ThisTime; if (ThisTime <= LastTime) { q->sched[0] = 0; return NO_TIME; } LastTime = ThisTime; q->ntrig++; } } /***************************************************************/ /* */ /* DaemonWait */ /* */ /* Sleep or read command from stdin in "daemon -1" mode */ /* */ /***************************************************************/ static void DaemonWait(unsigned int sleeptime) { fd_set readSet; struct timeval timeout; int retval; int y, m, d; char cmdLine[256]; FD_ZERO(&readSet); FD_SET(0, &readSet); timeout.tv_sec = sleeptime; timeout.tv_usec = 0; retval = select(1, &readSet, NULL, NULL, &timeout); /* If date has rolled around, restart */ if (RealToday != SystemDate(&y, &m, &d)) { printf("NOTE newdate\nNOTE reread\n"); fflush(stdout); reread(); } /* If nothing readable or interrupted system call, return */ if (retval <= 0) return; /* If stdin not readable, return */ if (!FD_ISSET(0, &readSet)) return; /* If EOF on stdin, exit */ if (feof(stdin)) { exit(0); } /* Read a line from stdin and interpret it */ if (!fgets(cmdLine, sizeof(cmdLine), stdin)) { exit(0); } if (!strcmp(cmdLine, "EXIT\n")) { exit(0); } else if (!strcmp(cmdLine, "STATUS\n")) { int nqueued = 0; QueuedRem *q = QueueHead; while(q) { if (q->tt.nexttime != NO_TIME) { nqueued++; } q = q->next; } printf("NOTE queued %d\n", nqueued); fflush(stdout); } else if (!strcmp(cmdLine, "REREAD\n")) { printf("NOTE reread\n"); fflush(stdout); reread(); } else { printf("ERR Invalid daemon command: %s", cmdLine); fflush(stdout); } } /***************************************************************/ /* */ /* reread */ /* */ /* Restarts Remind if date rolls over or REREAD cmd received */ /* */ /***************************************************************/ static void reread(void) { execvp(ArgV[0], (char **) ArgV); } remind-03.01.15/src/rem2ps.c0000644000076400007640000010151312514120517013503 0ustar dfsdfs/***************************************************************/ /* */ /* REM2PS.C */ /* */ /* Print a PostScript calendar. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "version.h" #include "config.h" #include "dynbuf.h" #include #include #include #include #include #include "rem2ps.h" #define NEW(type) (malloc(sizeof(type))) #define SPECIAL_NORMAL 0 #define SPECIAL_POSTSCRIPT 1 #define SPECIAL_PSFILE 2 #define SPECIAL_MOON 3 #define SPECIAL_COLOR 4 #define SPECIAL_WEEK 5 #define SPECIAL_SHADE 6 /* Array holding how specials sort */ static int SpecialSortOrder[] = { 0, /* NORMAL */ 1, /* POSTSCRIPT */ 1, /* PSFILE */ 2, /* MOON */ 0, /* COLOR */ 4, /* WEEK */ 5 /* SHADE */ }; typedef struct calentry { struct calentry *next; int special; char *entry; } CalEntry; typedef struct { char const *name; int xsize, ysize; } PageType; char DayName[7][33]; char const *SmallCalLoc[] = { "", "bt", "tb", "sbt", }; #define NUMSMALL (sizeof(SmallCalLoc)/sizeof(SmallCalLoc[0])) char const *SmallLocation; int SmallCol1, SmallCol2; PageType Pages[] = { {"Letter", 612, 792}, /* 8.5 x 11 in. */ {"Tabloid", 792, 1224}, /* 11 x 17 in. */ {"Ledger", 1224, 792}, /* 17 x 11 in. */ {"Legal", 612, 1008}, /* 8.5 x 14 in. */ {"Statement", 396, 612}, /* 5.5 x 8.5 in. */ {"Executive", 540, 720}, /* 7.5 x 10 in. */ {"A3", 842, 1190}, {"A4", 595, 842}, {"A5", 420, 595}, {"B4", 729, 1032}, {"B5", 519, 729}, {"Folio", 612, 936}, {"Quarto", 612, 780}, {"10x14", 720, 1008}, {"-custom-", 0, 0} }; PageType DefaultPage[1] = { DEFAULT_PAGE }; #define NUMPAGES (sizeof(Pages)/sizeof(Pages[0])) CalEntry *CurEntries = NULL; CalEntry *PsEntries[32]; PageType *CurPage; char PortraitMode; char NoSmallCal; char UseISO; char const *HeadFont="Helvetica"; char const *TitleFont="Helvetica"; char const *DayFont="Helvetica-BoldOblique"; char const *EntryFont="Helvetica"; char const *SmallFont="Helvetica"; char const *LineWidth = "1"; char const *HeadSize="14"; char const *TitleSize="14"; char const *DaySize="14"; char const *EntrySize="8"; char const *BorderSize = "6"; char const *UserProlog = NULL; int validfile = 0; int CurDay; int MaxDay; int DayNum; int WkDayNum; int FirstWkDay; int MondayFirst; int LeftMarg, RightMarg, TopMarg, BotMarg; int FillPage; int Verbose = 0; void Init (int argc, char *argv[]); void Usage (char const *s); void DoPsCal (void); int DoQueuedPs (void); void DoSmallCal (char const *m, int days, int first, int col, int which); void WriteProlog (void); void WriteCalEntry (void); void WriteOneEntry (CalEntry *c); void GetSmallLocations (void); char const *EatToken(char const *in, char *out, int maxlen); /***************************************************************/ /* */ /* MAIN PROGRAM */ /* */ /***************************************************************/ int main(int argc, char *argv[]) { /* If stdin is a tty - probably wrong. */ DynamicBuffer buf; DBufInit(&buf); Init(argc, argv); if (isatty(0)) { Usage("Input should not come from a terminal"); } /* Search for a valid input file */ while (!feof(stdin)) { DBufGets(&buf, stdin); if (!strcmp(DBufValue(&buf), PSBEGIN)) { if (!validfile) { if (Verbose) { fprintf(stderr, "Rem2PS: Version %s Copyright 1992-1998 by Dianne Skoll\n\n", VERSION); fprintf(stderr, "Generating PostScript calendar\n"); } } validfile++; DoPsCal(); } } if (!validfile) { fprintf(stderr, "Rem2PS: Couldn't find any calendar data - are you\n"); fprintf(stderr, " sure you fed me input produced by remind -p ...?\n"); exit(1); } printf("%%%%Trailer\n"); printf("%%%%Pages: %d\n", validfile); if (Verbose) fprintf(stderr, "Rem2PS: Done\n"); return 0; } /***************************************************************/ /* */ /* DoPsCal - emit PostScript for the calendar. */ /* */ /***************************************************************/ void DoPsCal(void) { char month[40], year[40]; char prevm[40], nextm[40]; int days, wkday, prevdays, nextdays; int sfirst; int i; int is_ps; int firstcol; char const *startOfBody; char passthru[PASSTHRU_LEN+1]; DynamicBuffer buf; CalEntry *c, *d, *p; /* Read the month and year name, followed by # days in month and 1st day of month */ DBufInit(&buf); DBufGets(&buf, stdin); sscanf(DBufValue(&buf), "%s %s %d %d %d", month, year, &days, &wkday, &MondayFirst); /* Get day names */ DBufGets(&buf, stdin); sscanf(DBufValue(&buf), "%32s %32s %32s %32s %32s %32s %32s", DayName[0], DayName[1], DayName[2], DayName[3], DayName[4], DayName[5], DayName[6]); /* We write the prolog here because it's only at this point that MondayFirst is set correctly. */ if (validfile == 1) { WriteProlog(); } DBufGets(&buf, stdin); sscanf(DBufValue(&buf), "%s %d", prevm, &prevdays); DBufGets(&buf, stdin); sscanf(DBufValue(&buf), "%s %d", nextm, &nextdays); DBufFree(&buf); MaxDay = days; FirstWkDay = wkday; /* Print a message for the user */ if (Verbose) fprintf(stderr, " %s %s\n", month, year); printf("%%%%Page: %c%c%c%c%c %d\n", month[0], month[1], month[2], year[2], year[3], validfile); /* Emit PostScript to do the heading */ if (!PortraitMode) printf("90 rotate 0 XSIZE neg translate\n"); printf("/SAVESTATE save def (%s) (%s) PreCal SAVESTATE restore\n", month, year); printf("(%s %s) doheading\n", month, year); /* Figure out the column of the first day in the calendar */ if (MondayFirst) { firstcol = wkday-1; if (firstcol < 0) firstcol = 6; } else { firstcol = wkday; } /* Calculate the minimum box size */ if (!FillPage) { printf("/MinBoxSize ytop MinY sub 7 div def\n"); } else { if ((days == 31 && firstcol >= 5) || (days == 30 && firstcol == 6)) printf("/MinBoxSize ytop MinY sub 6 div def\n"); else if (days == 28 && firstcol == 0 && NoSmallCal) printf("/MinBoxSize ytop MinY sub 4 div def\n"); else printf("/MinBoxSize ytop MinY sub 5 div def\n"); } printf("/ysmalltop ytop def\n"); /* Do each entry */ CurEntries = NULL; CurDay = 1; WkDayNum = wkday; while(1) { if (feof(stdin)) { fprintf(stderr, "Input from REMIND is corrupt!\n"); exit(1); } DBufGets(&buf, stdin); if (!strcmp(DBufValue(&buf), PSEND)) { DBufFree(&buf); break; } /* Ignore lines beginning with '#' */ if (DBufValue(&buf)[0] == '#') { continue; } /* Read the day number - a bit of a hack! */ DayNum = (DBufValue(&buf)[8] - '0') * 10 + DBufValue(&buf)[9] - '0'; if (DayNum != CurDay) { for(; CurDaynext = NULL; c->special = SPECIAL_NORMAL; /* Skip the tag, duration and time */ startOfBody = DBufValue(&buf)+10; /* Eat the passthru */ startOfBody = EatToken(startOfBody, passthru, PASSTHRU_LEN); /* Eat the tag */ startOfBody = EatToken(startOfBody, NULL, 0); /* Eat the duration */ startOfBody = EatToken(startOfBody, NULL, 0); /* Eat the time */ startOfBody = EatToken(startOfBody, NULL, 0); is_ps = 0; if (!strcmp(passthru, "PostScript") || !strcmp(passthru, "PSFile") || !strcmp(passthru, "MOON") || !strcmp(passthru, "WEEK") || !strcmp(passthru, "SHADE")) { is_ps = 1; } c->entry = malloc(strlen(startOfBody) + 1); if (!c->entry) { fprintf(stderr, "malloc failed - aborting.\n"); exit(1); } strcpy(c->entry, startOfBody); if (is_ps) { /* Save the type of SPECIAL */ if (!strcmp(passthru, "PostScript")) { c->special = SPECIAL_POSTSCRIPT; } else if (!strcmp(passthru, "SHADE")) { c->special = SPECIAL_SHADE; } else if (!strcmp(passthru, "MOON")) { c->special = SPECIAL_MOON; } else if (!strcmp(passthru, "WEEK")) { c->special = SPECIAL_WEEK; } else { c->special = SPECIAL_PSFILE; } if (!PsEntries[DayNum]) { PsEntries[DayNum] = c; } else { d = PsEntries[DayNum]; p = NULL; /* Slot it into the right place */ while (d->next && (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special])) { p = d; d = d->next; } if (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special]) { c->next = d->next; d->next = c; } else { if (p) { p->next = c; } else { PsEntries[DayNum] = c; } c->next = d; } } } else if (!strcmp(passthru, "*") || !strcmp(passthru, "COLOUR") || !strcmp(passthru, "COLOR")) { /* Put on linked list */ if (!CurEntries) { CurEntries = c; } else { d = CurEntries; while(d->next) d = d->next; d->next = c; } if (!strcmp(passthru, "COLOR") || !strcmp(passthru, "COLOUR")) { c->special = SPECIAL_COLOR; } } } for(; CurDay<=days; CurDay++) { WriteCalEntry(); WkDayNum = (WkDayNum + 1) % 7; } /* If wkday < 2, set ysmall. If necessary (only for feb) increase cal size. */ printf("/ysmallbot ylast def\n"); /* Now draw the vertical lines */ GetSmallLocations(); for (i=0; i<=7; i++) { printf("%d xincr mul MinX add ymin %d xincr mul MinX add topy L\n", i, i); } /* print the small calendars */ if (!NoSmallCal) { sfirst = wkday - (prevdays % 7); if (sfirst < 0) sfirst += 7; DoSmallCal(prevm, prevdays, sfirst, SmallCol1, 1); sfirst = wkday + (days % 7); if (sfirst >6) sfirst -= 7; DoSmallCal(nextm, nextdays, sfirst, SmallCol2, 2); } /* Do it! */ printf("showpage\n"); } /***************************************************************/ /* */ /* WriteProlog - write the PostScript prologue */ /* */ /***************************************************************/ void WriteProlog(void) { int i; int x = CurPage->xsize; int y = CurPage->ysize; char const *isostuff; FILE *fp; int nread; char buffer[512]; if (!PortraitMode) { i = x; x = y; y = i; } if (UseISO) isostuff = "reencodeISO"; else isostuff = "copyFont"; /* Write the document structuring stuff */ printf("%%!PS-Adobe-2.0\n"); printf("%%%%DocumentFonts: %s", HeadFont); if (strcmp(TitleFont, HeadFont)) printf(" %s", TitleFont); if (strcmp(TitleFont, DayFont) && strcmp(HeadFont, DayFont)) printf(" %s", DayFont); if (strcmp(EntryFont, HeadFont) && strcmp(TitleFont, EntryFont) && strcmp(EntryFont, DayFont)) printf(" %s", EntryFont); if (!NoSmallCal && strcmp(SmallFont, HeadFont) && strcmp(SmallFont, DayFont) && strcmp(TitleFont, SmallFont) && strcmp(SmallFont, EntryFont)) printf(" %s", SmallFont); PutChar('\n'); printf("%%%%Creator: Rem2PS\n"); printf("%%%%Pages: (atend)\n"); printf("%%%%Orientation: %s\n", PortraitMode ? "Portrait" : "Landscape"); printf("%%%%EndComments\n"); for (i=0; PSProlog1[i]; i++) puts(PSProlog1[i]); if (!MondayFirst) printf("[(%s) (%s) (%s) (%s) (%s) (%s) (%s)]\n", DayName[0], DayName[1], DayName[2], DayName[3], DayName[4], DayName[5], DayName[6]); else printf("[(%s) (%s) (%s) (%s) (%s) (%s) (%s)]\n", DayName[1], DayName[2], DayName[3], DayName[4], DayName[5], DayName[6], DayName[0]); for (i=0; PSProlog2[i]; i++) puts(PSProlog2[i]); printf("/HeadFont /%s %s\n", HeadFont, isostuff); if (!NoSmallCal) printf("/SmallFont /%s %s\n", SmallFont, isostuff); printf("/DayFont /%s %s\n", DayFont, isostuff); printf("/EntryFont /%s %s\n", EntryFont, isostuff); printf("/TitleFont /%s %s\n", TitleFont, isostuff); printf("/HeadSize %s def\n", HeadSize); printf("/DaySize %s def\n", DaySize); printf("/EntrySize %s def\n", EntrySize); printf("/TitleSize %s def\n", TitleSize); printf("/XSIZE %d def\n", CurPage->xsize); printf("/MinX %d def\n", LeftMarg); printf("/MinY %d def\n", BotMarg); printf("/MaxX %d def\n", x-RightMarg); printf("/MaxY %d def\n", y-TopMarg); printf("/Border %s def\n", BorderSize); printf("/LineWidth %s def\n", LineWidth); printf("%s setlinewidth\n", LineWidth); /* Check if smallfont is fixed pitch */ if (!NoSmallCal) { printf("/SmallFont findfont /FontInfo get /isFixedPitch get\n"); /* Define SmallString used to set smallfont size */ printf("{/SmallString (WW ) def}\n"); printf("{/SmallString (WW) def}\nifelse\n"); } /* Do the user-supplied prolog file, if any */ if (UserProlog) { fp = fopen(UserProlog, "r"); if (!fp) { fprintf(stderr, "Could not open prologue file `%s'\n", UserProlog); } else { while(1) { nread = fread(buffer, sizeof(char), 512, fp); if (!nread) break; fwrite(buffer, sizeof(char), nread, stdout); } fclose(fp); } } printf("%%%%EndProlog\n"); } /***************************************************************/ /* */ /* WriteCalEntry - write all entries for one day */ /* */ /***************************************************************/ void WriteCalEntry(void) { CalEntry *c = CurEntries; CalEntry *d; int begin, end, i, HadQPS; /* Move to appropriate location */ printf("/CAL%d {\n", CurDay); if (!MondayFirst) printf("Border ytop %d xincr mul MinX add xincr\n", WkDayNum); else printf("Border ytop %d xincr mul MinX add xincr\n", (WkDayNum ? WkDayNum-1 : 6)); /* Set up the text array */ printf("[\n"); CurEntries = NULL; while(c) { WriteOneEntry(c); free(c->entry); d = c->next; free(c); c = d; } printf("]\n"); /* Print the day number */ printf("(%d)\n", CurDay); /* Do it! */ printf("DoCalBox\n"); /* Update ymin */ printf("/y exch def y ymin lt {/ymin y def} if\n"); printf("} def\n"); /* If WkDayNum is a Sunday or Monday, depending on MondayFirst, move to next row. Also handle the queued PS and PSFILE reminders */ if ((!MondayFirst && WkDayNum == 6) || (MondayFirst && WkDayNum == 0) || CurDay == MaxDay) { HadQPS = 0; if (MondayFirst) begin = CurDay - (WkDayNum ? WkDayNum-1 : 6); else begin = CurDay - WkDayNum; if (begin < 1) begin = 1; end = CurDay; for (i=begin; i<=end; i++) { if (PsEntries[i]) { HadQPS = 1; break; } } /* Avoid problems with blotching if PS printer has roundoff errors */ if (HadQPS) printf("1 setgray\n"); for (i=begin; i<=end; i++) { printf("CAL%d\n", i); } if (HadQPS) printf("0 setgray\n"); printf("/y ytop MinBoxSize sub def y ymin lt {/ymin y def} if\n"); /* Draw the line at the bottom of the row */ printf("MinX ymin MaxX ymin L\n"); /* Update ytop */ printf("/ylast ytop def\n"); printf("/ytop ymin def\n"); (void) DoQueuedPs(); /* Re-do the calendar stuff if there was any included PS code */ if (HadQPS) { printf("/ytop ylast def\n"); for (i=begin; i<=end; i++) { printf("CAL%d\n", i); } printf("/y ytop MinBoxSize sub def y ymin lt {/ymin y def} if\n"); printf("MinX ymin MaxX ymin L\n"); printf("/ylast ytop def\n"); printf("/ytop ymin def\n"); } } } /***************************************************************/ /* */ /* WriteOneEntry - write an entry for one day */ /* */ /***************************************************************/ void WriteOneEntry(CalEntry *c) { int ch, i; char const *s = c->entry; printf(" ["); /* Chew up leading spaces */ while(isspace((unsigned char) *s)) s++; /* Skip three decimal numbers for COLOR special */ if (c->special == SPECIAL_COLOR) { for (i=0; i<3; i++) { while(*s && !isspace(*s)) s++; while(*s && isspace(*s)) s++; } } PutChar('('); while(*s) { /* Use the "unsigned char" cast to fix problem on Solaris 2.5 */ /* which treated some latin1 characters as white space. */ ch = (unsigned char) *s++; if (ch == '\\' || ch == '(' || ch == ')') PutChar('\\'); if (!isspace(ch)) PutChar(ch); else { PutChar(')'); while(isspace((unsigned char)*s)) s++; if (!*s) { goto finish; } PutChar('('); } } printf(")\n"); finish: if (c->special == SPECIAL_COLOR) { int r, g, b; if (sscanf(c->entry, "%d %d %d", &r, &g, &b) == 3) { if (r < 0) r = 0; else if (r > 255) r = 255; if (g < 0) g = 0; else if (g > 255) g = 255; if (b < 0) b = 0; else if (b > 255) b = 255; printf("(gsave %f %f %f setrgbcolor)(grestore)", r / 255.0, g / 255.0, b / 255.0); } else { /* Punt... unrecognized color is black */ printf("()()"); } } else { printf("()()"); } printf("]\n"); } /***************************************************************/ /* */ /* Init - set up parameters */ /* */ /***************************************************************/ void Init(int argc, char *argv[]) { char const *s; char const *t; int i=1; int j; int offset; PortraitMode = 1; NoSmallCal = 0; LeftMarg = 36; RightMarg = 36; TopMarg = 36; BotMarg = 36; UseISO = 0; FillPage = 0; MondayFirst = 0; SmallLocation = "bt"; for(j=0; j<32; j++) PsEntries[i] = NULL; CurPage = DefaultPage; /* Letter size by default */ while (i < argc) { s = argv[i]; i++; if (*s++ != '-') Usage("Options must begin with `-'"); switch(*s++) { case 'p': if (i == argc) Usage("Prologue filename must be supplied"); UserProlog = argv[i++]; break; case 's': if (i == argc) Usage("Size must be supplied"); t = argv[i++]; while(*s) { switch(*s++) { case 'h': HeadSize = t; break; case 'e': EntrySize = t; break; case 'd': DaySize = t; break; case 't': TitleSize = t; break; default: Usage("Size must specify h, t, e, or d"); } } break; case 'f': if (i == argc) Usage("Font must be supplied"); t = argv[i++]; while(*s) { switch(*s++) { case 'h': HeadFont = t; break; case 'e': EntryFont = t; break; case 'd': DayFont = t; break; case 's': SmallFont = t; break; case 't': TitleFont = t; break; default: Usage("Font must specify s, h, t, e, or d"); } } break; case 'v': Verbose = 1; break; case 'm': if (i == argc) Usage("Media must be supplied"); t = argv[i++]; CurPage = NULL; for (j=0; jxsize = (int) (w * 72.0); CurPage->ysize = (int) (h * 72.0); } else if (sscanf(t, "%lfx%lfcm", &w, &h) == 2) { CurPage = &Pages[NUMPAGES-1]; CurPage->xsize = (int) ((double) w * 28.346457); CurPage->ysize = (int) ((double) w * 28.346457); } } if (!CurPage) { fprintf(stderr, "\nUnknown media specified.\n"); fprintf(stderr, "\nAvailable media types:\n"); for (j=0; j=0 && jentry+fnoff))) fnoff++; switch(e->special) { case SPECIAL_POSTSCRIPT: /* Send PostScript through */ printf("%s\n", e->entry+fnoff); break; case SPECIAL_PSFILE: /* PostScript from a file */ fp = fopen(e->entry+fnoff, "r"); if (!fp) { fprintf(stderr, "Could not open PostScript file `%s'\n", e->entry+1); } else { while(1) { nread = fread(buffer, sizeof(char), 512, fp); if (!nread) break; fwrite(buffer, sizeof(char), nread, stdout); } fclose(fp); } break; case SPECIAL_SHADE: /* Shading */ num = sscanf(e->entry+fnoff, "%d %d %d", &r, &g, &b); if (num == 1) { g = r; b = r; } else if (num != 3) { fprintf(stderr, "Rem2PS: Malformed SHADE special\n"); break; } if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { fprintf(stderr, "Rem2PS: Illegal values for SHADE\n"); break; } printf("/_A LineWidth 2 div def _A _A moveto\n"); printf("BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto\n"); printf("_A BoxHeight _A sub lineto closepath\n"); printf("%g %g %g setrgbcolor fill 0.0 setgray\n", r/255.0, g/255.0, b/255.0); break; case SPECIAL_WEEK: /* Week number */ printf("gsave Border Border 2 div moveto /EntryFont findfont EntrySize 1.2 div scalefont setfont ("); s = e->entry+fnoff; while(*s && isspace(*s)) { s++; } while(*s) { if (*s == '\\' || *s == '(' || *s == ')') { PutChar('\\'); } PutChar(*s); s++; } printf(") show grestore\n"); break; case SPECIAL_MOON: /* Moon phase */ num = sscanf(e->entry+fnoff, "%d %d %d", &phase, &moonsize, &fontsize); if (num == 1) { moonsize = -1; fontsize = -1; } else if (num == 2) { fontsize = -1; } else if (num != 3) { fprintf(stderr, "Rem2PS: Badly formed MOON special\n"); break; } if (phase < 0 || phase > 3) { fprintf(stderr, "Rem2PS: Illegal MOON phase %d\n", phase); break; } if (moonsize < 0) { size = "DaySize 2 div"; } else { sprintf(buffer, "%d", moonsize); size = buffer; } printf("gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub\n", size, size); printf(" %s 0 360 arc closepath\n", size); switch(phase) { case 0: printf("fill\n"); break; case 2: printf("stroke\n"); break; case 1: printf("stroke\n"); printf("newpath Border %s add BoxHeight Border sub %s sub\n", size, size); printf("%s 90 270 arc closepath fill\n", size); break; default: printf("stroke\n"); printf("newpath Border %s add BoxHeight Border sub %s sub\n", size, size); printf("%s 270 90 arc closepath fill\n", size); break; } /* See if we have extra stuff */ extra = e->entry+fnoff; /* Skip phase */ while(*extra && !isspace(*extra)) extra++; while(*extra && isspace(*extra)) extra++; /* Skip moon size */ while(*extra && !isspace(*extra)) extra++; while(*extra && isspace(*extra)) extra++; /* Skip font size */ while(*extra && !isspace(*extra)) extra++; while(*extra && isspace(*extra)) extra++; /* Anything left? */ if (*extra) { printf("Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto\n", size, size, size, size); if (fontsize < 0) { size = "EntrySize"; } else { sprintf(buffer, "%d", fontsize); size = buffer; } printf("/EntryFont findfont %s scalefont setfont (", size); while(*extra) { c = (unsigned char) *extra++; if (c == '\\' || c == '(' || c == ')') PutChar('\\'); PutChar(c); } printf(") show\n"); } printf("grestore\n"); break; } /* Free the entry */ free(e->entry); n = e->next; free(e); e = n; } if (PsEntries[i]) printf("\n SAVESTATE restore\n"); PsEntries[i] = NULL; } return HadPS; } /***************************************************************/ /* */ /* GetSmallLocations */ /* */ /* Set up the locations for the small calendars. */ /* */ /***************************************************************/ void GetSmallLocations(void) { char c; char const *s = SmallLocation; int colfirst, collast; /* Figure out the first and last columns */ colfirst = FirstWkDay; collast = (FirstWkDay+MaxDay-1) % 7; if (MondayFirst) { colfirst = colfirst ? colfirst - 1 : 6; collast = collast ? collast - 1 : 6; } NoSmallCal = 0; while((c = *s++) != 0) { switch(c) { case 'b': /* Adjust Feb. if we want it on the bottom */ if (MaxDay == 28 && colfirst == 0) { printf("/ysmallbot ymin def /ymin ysmallbot MinBoxSize sub def\n"); printf("MinX ymin MaxX ymin L\n"); printf("/ysmall1 ysmallbot def /ysmall2 ysmallbot def\n"); SmallCol1 = 5; SmallCol2 = 6; return; } if (collast <= 4) { printf("/ysmall1 ysmallbot def /ysmall2 ysmallbot def\n"); SmallCol1 = 5; SmallCol2 = 6; return; } break; case 't': if (colfirst >= 2) { printf("/ysmall1 ysmalltop def /ysmall2 ysmalltop def\n"); SmallCol1 = 0; SmallCol2 = 1; return; } break; case 's': if (colfirst >= 1 && collast<=5) { printf("/ysmall1 ysmalltop def /ysmall2 ysmallbot def\n"); SmallCol1 = 0; SmallCol2 = 6; return; } break; } } NoSmallCal = 1; return; } /***************************************************************/ /* */ /* EatToken */ /* */ /* Read a space-delimited token into an output buffer. */ /* */ /***************************************************************/ char const *EatToken(char const *in, char *out, int maxlen) { int i = 0; /* Skip space before token */ while(*in && isspace(*in)) in++; /* Eat the token */ while(*in && !isspace(*in)) { if (i < maxlen) { if (out) *out++ = *in; i++; } in++; } if (out) *out = 0; return in; } remind-03.01.15/src/rem2ps.h0000644000076400007640000002061612514120501013505 0ustar dfsdfs/***************************************************************/ /* */ /* REM2PS.H */ /* */ /* Define the PostScript prologue */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ char *PSProlog1[] = { "% This file was produced by Remind and Rem2PS, written by", "% Dianne Skoll.", "% Remind and Rem2PS are Copyright 1992-1997 Dianne Skoll.", "/ISOLatin1Encoding where { pop save true }{ false } ifelse", " /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus", " StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute", " /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring", " /cedilla /.notdef /hungarumlaut /ogonek /caron /space /exclamdown /cent", " /sterling /currency /yen /brokenbar /section /dieresis /copyright", " /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron", " /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph", " /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright", " /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute", " /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute", " /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth", " /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply", " /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn", " /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae", " /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute", " /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex", " /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex", " /udieresis /yacute /thorn /ydieresis ] def", "{ restore } if", "", "/reencodeISO { %def", " findfont dup length dict begin", " { 1 index /FID ne { def }{ pop pop } ifelse } forall", " /Encoding ISOLatin1Encoding def", " currentdict end definefont pop", "} bind def", "/copyFont { %def", " findfont dup length dict begin", " { 1 index /FID ne { def } { pop pop } ifelse } forall", " currentdict end definefont pop", "} bind def", "", "% L - Draw a line", "/L {", " newpath moveto lineto stroke", "} bind def", "% string1 string2 strcat string", "% Function: Concatenates two strings together.", "/strcat {", " 2 copy length exch length add", " string dup", " 4 2 roll", " 2 index 0 3 index", " putinterval", " exch length exch putinterval", "} bind def", "% string doheading", "/doheading", "{", " /monthyr exch def", "", " /TitleFont findfont", " TitleSize scalefont setfont", " monthyr stringwidth", " /hgt exch def", " 2 div MaxX MinX add 2 div exch sub /x exch def", " MaxY Border sub TitleSize sub /y exch def", " newpath x y moveto monthyr show", " newpath x y moveto monthyr false charpath flattenpath pathbbox", " pop pop Border sub /y exch def pop", " MinX y MaxX y L", " /topy y def", " /HeadFont findfont HeadSize scalefont setfont", "% Do the days of the week", " MaxX MinX sub 7 div /xincr exch def", " /x MinX def", NULL }; char *PSProlog2[] = { " {", " HeadSize x y HeadSize 2 mul sub x xincr add y CenterText", " x xincr add /x exch def", " } forall", " y HeadSize 2 mul sub /y exch def", " MinX y MaxX y L", " /ytop y def /ymin y def", "}", "def", "/CenterText", "{", " /maxy exch def", " /maxx exch def", " /miny exch def", " /minx exch def", " /sz exch def", " /str exch def", " str stringwidth pop", " 2 div maxx minx add 2 div exch sub", " sz 2 div maxy miny add 2 div exch sub", " moveto str show", "} def", "% Variables:", "% curline - a string holding the current line", "% y - current y pos", "% yincr - increment to next line", "% xleft - left margin", "% width - max width.", "% EnterOneWord - given a word, enter it into the box.", "% string EnterOneWord", "/EnterOneWord {", " { EnterOneWordAux", " {exit} if }", " loop", "} bind def", "% EnterOneWordAux - if the word fits, enter it into box and return true.", "% If it doesn't fit, put as much as will fit and return the string and false.", "/EnterOneWordAux {", " /word exch def", " /tmpline curline word strcat def", " tmpline stringwidth pop width gt", " {MoveToNewLine}", " {/curline tmpline ( ) strcat def /word () def}", " ifelse", " word () eq", " {true}", " {word false}", " ifelse", "} bind def", "% MoveToNewLine - move to a new line, resetting word as appropriate", "/MoveToNewLine {", " curline () ne", " {newpath xleft y moveto curline show /curline () def /y y yincr add def} ", " {ChopWord}", " ifelse", "} bind def", "% ChopWord - word won't fit. Chop it and find biggest piece that will fit", "/ChopWord {", " /curline () def", " /len word length def", " /Fcount len 1 sub def", "", " {", " word 0 Fcount getinterval stringwidth pop width le", " {exit} if", " /Fcount Fcount 1 sub def", " } loop", "% Got the count. Display it and reset word", " newpath xleft y moveto word 0 Fcount getinterval show", " /y y yincr add def", " /word word Fcount len Fcount sub getinterval def", "} bind def", "/FinishFormatting {", " word () ne", " {newpath xleft y moveto word show /word () def", " /curline () def /y y yincr add def}", " {curline () ne", " {newpath xleft y moveto curline show /word () def", " /curline () def /y y yincr add def} if}", " ifelse", "} bind def", "% FillBoxWithText - fill a box with text", "% text-array xleft width yincr y FillBoxWithText new-y", "% Returns the new Y-coordinate.", "/FillBoxWithText {", " /y exch def", " /yincr exch def", " /width exch def", " /xleft exch def", " /curline () def", " % The last two strings in the word array are actually the PostScript", " % code to execute before and after the entry is printed.", " dup dup", " length 1 sub", " get", " exch", " dup dup", " length 2 sub", " get", " dup length 0 gt", " {cvx exec} {pop} ifelse", " dup length 2 sub 0 exch getinterval", " {EnterOneWord} forall", " FinishFormatting", " dup length 0 gt", " {cvx exec} {pop} ifelse", " y", "} bind def", "% Variables for calendar boxes:", "% ytop - current top position", "% ymin - minimum y reached for current row", "% border ytop xleft width textarray daynum DoCalBox ybot", "% Do the entries for one calendar box. Returns lowest Y-coordinate reached", "/DoCalBox {", " /daynum exch def", " /textarr exch def", " /wid exch def", " /xl exch def", " /yt exch def", " /border exch def", "% Do the day number", " /DayFont findfont DaySize scalefont setfont", " xl wid add border sub daynum stringwidth pop sub", " yt border sub DaySize sub moveto daynum show", "% Do the text entries. Precharge the stack with current y pos.", " /ycur yt border sub DaySize sub DaySize sub 2 add def", " /EntryFont findfont EntrySize scalefont setfont", " ycur", " textarr", " { exch 2 sub /ycur exch def xl border add wid border sub border sub EntrySize 2 add neg", " ycur FillBoxWithText }", " forall", "} bind def", "2 setlinecap", "% Define a default PreCal procedure", "/PreCal { pop pop } bind def", NULL }; remind-03.01.15/src/sort.c0000644000076400007640000001607712514120475013277 0ustar dfsdfs/***************************************************************/ /* */ /* SORT.C */ /* */ /* Routines for sorting reminders by trigger date */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include "types.h" #include "protos.h" #include "expr.h" #include "globals.h" #include "err.h" /* The structure of a sorted entry */ typedef struct sortrem { struct sortrem *next; char const *text; int trigdate; int trigtime; int typ; int priority; } Sortrem; /* The sorted reminder queue */ static Sortrem *SortedQueue = (Sortrem *) NULL; static Sortrem *MakeSortRem (int jul, int tim, char const *body, int typ, int prio); static void IssueSortBanner (int jul); /***************************************************************/ /* */ /* MakeSortRem */ /* */ /* Create a new Sortrem entry - return NULL on failure. */ /* */ /***************************************************************/ static Sortrem *MakeSortRem(int jul, int tim, char const *body, int typ, int prio) { Sortrem *new = NEW(Sortrem); if (!new) return NULL; new->text = StrDup(body); if (!new->text) { free(new); return NULL; } new->trigdate = jul; new->trigtime = tim; new->typ = typ; new->priority = prio; new->next = NULL; return new; } /***************************************************************/ /* */ /* InsertIntoSortBuffer */ /* */ /* Insert a reminder into the sort buffer */ /* */ /***************************************************************/ int InsertIntoSortBuffer(int jul, int tim, char const *body, int typ, int prio) { Sortrem *new = MakeSortRem(jul, tim, body, typ, prio); Sortrem *cur = SortedQueue, *prev = NULL; int ShouldGoAfter; if (!new) { Eprint("%s", ErrMsg[E_NO_MEM]); IssueSortedReminders(); SortByDate = 0; SortByTime = 0; SortByPrio = 0; UntimedBeforeTimed = 0; return E_NO_MEM; } /* Find the correct place in the sorted list */ if (!SortedQueue) { SortedQueue = new; return OK; } while (cur) { ShouldGoAfter = CompareRems(new->trigdate, new->trigtime, new->priority, cur->trigdate, cur->trigtime, cur->priority, SortByDate, SortByTime, SortByPrio, UntimedBeforeTimed); if (ShouldGoAfter <= 0) { prev = cur; cur = cur->next; } else { if (prev) { prev->next = new; new->next = cur; } else { SortedQueue = new; new->next = cur; } return OK; } } prev->next = new; new->next = cur; /* For safety - actually redundant */ return OK; } /***************************************************************/ /* */ /* IssueSortedReminders */ /* */ /* Issue all of the sorted reminders and free memory. */ /* */ /***************************************************************/ void IssueSortedReminders(void) { Sortrem *cur = SortedQueue; Sortrem *next; int olddate = NO_DATE; while (cur) { next = cur->next; switch(cur->typ) { case MSG_TYPE: if (MsgCommand) { DoMsgCommand(MsgCommand, cur->text); } else { if (cur->trigdate != olddate) { IssueSortBanner(cur->trigdate); olddate = cur->trigdate; } printf("%s", cur->text); } break; case MSF_TYPE: FillParagraph(cur->text); break; case RUN_TYPE: system(cur->text); break; } free((char *) cur->text); free(cur); cur = next; } SortedQueue = NULL; } /***************************************************************/ /* */ /* IssueSortBanner */ /* */ /* Issue a daily banner if the function sortbanner() is */ /* defined to take one argument. */ /* */ /***************************************************************/ static void IssueSortBanner(int jul) { char BanExpr[64]; int y, m, d; Value v; char const *s = BanExpr; DynamicBuffer buf; if (UserFuncExists("sortbanner") != 1) return; FromJulian(jul, &y, &m, &d); sprintf(BanExpr, "sortbanner('%04d/%02d/%02d')", y, m+1, d); y = EvalExpr(&s, &v, NULL); if (y) return; if (DoCoerce(STR_TYPE, &v)) return; DBufInit(&buf); if (!DoSubstFromString(v.v.str, &buf, jul, NO_TIME)) { if (*DBufValue(&buf)) printf("%s\n", DBufValue(&buf)); DBufFree(&buf); } DestroyValue(v); } /***************************************************************/ /* */ /* CompareRems */ /* */ /* Compare two reminders for sorting. Return 0 if they */ /* compare equal; 1 if rem2 should come after rem1, -1 if */ /* rem1 should come after rem2. bydate and bytime control */ /* sorting direction by date and time, resp. */ /* */ /***************************************************************/ int CompareRems(int dat1, int tim1, int prio1, int dat2, int tim2, int prio2, int bydate, int bytime, int byprio, int untimed_first) { int dafter, tafter, pafter, uafter; dafter = (bydate != SORT_DESCEND) ? 1 : -1; tafter = (bytime != SORT_DESCEND) ? 1 : -1; pafter = (byprio != SORT_DESCEND) ? 1 : -1; uafter = (untimed_first) ? -1 : 1; if (dat1 < dat2) return dafter; if (dat1 > dat2) return -dafter; if (tim1 == NO_TIME && tim2 != NO_TIME) { return -uafter; } if (tim1 != NO_TIME && tim2 == NO_TIME) { return uafter; } if (tim1 < tim2) return tafter; if (tim1 > tim2) return -tafter; if (prio1 < prio2) return pafter; if (prio1 > prio2) return -pafter; return 0; } remind-03.01.15/src/test-all-languages.sh0000755000076400007640000000046011707311120016151 0ustar dfsdfs#!/bin/sh # Make sure Remind compiles with all supported languages; show # tstlang.rem output for each language. ALL=`grep ^#define lang.h | grep -v '#define LANG' | awk '{print $2}'` for i in $ALL ; do make clean all LANGDEF=-DLANG=$i || exit 1 ./remind -q -r ../tests/tstlang.rem done exit 0 remind-03.01.15/src/token.c0000644000076400007640000002750512514120472013423 0ustar dfsdfs/***************************************************************/ /* */ /* TOKEN.C */ /* */ /* Contains routines for parsing the reminder file and */ /* classifying the tokens parsed. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #include "types.h" #include "globals.h" #include "protos.h" #include "err.h" /* The macro PARSENUM parses a char pointer as an integer. It simply executes 'return' if an initial non-numeric char is found. */ #define PARSENUM(var, string) \ if (!isdigit(*(string))) return; \ var = 0; \ while (isdigit(*(string))) { \ var *= 10; \ var += *(string) - '0'; \ string++; \ } /* The big array holding all recognized (literal) tokens in reminder file. Keep this array sorted, or software will not work. */ Token TokArray[] = { /* NAME MINLEN TYPE VALUE */ { "after", 3, T_Skip, AFTER_SKIP }, { "april", 3, T_Month, 3 }, { "at", 2, T_At, 0 }, { "august", 3, T_Month, 7 }, { "banner", 3, T_Banner, 0 }, { "before", 3, T_Skip, BEFORE_SKIP }, { "cal", 3, T_RemType, CAL_TYPE }, { "clear-omit-context", 5, T_Clr, 0 }, { "debug", 5, T_Debug, 0 }, { "december", 3, T_Month, 11 }, { "dumpvars", 4, T_Dumpvars, 0 }, { "duration", 3, T_Duration, 0 }, { "else", 4, T_Else, 0 }, { "endif", 5, T_EndIf, 0 }, { "errmsg", 6, T_ErrMsg, 0 }, { "exit", 4, T_Exit, 0 }, { "february", 3, T_Month, 1 }, { "flush", 5, T_Flush, 0 }, { "friday", 3, T_WkDay, 4 }, { "from", 4, T_Scanfrom, FROM_TYPE }, { "fset", 4, T_Fset, 0 }, { "if", 2, T_If, 0 }, { "iftrig", 6, T_IfTrig, 0 }, { "include", 3, T_Include, 0 }, { "january", 3, T_Month, 0 }, { "july", 3, T_Month, 6 }, { "june", 3, T_Month, 5 }, { "march", 3, T_Month, 2 }, { "may", 3, T_Month, 4 }, { "monday", 3, T_WkDay, 0 }, { "msf", 3, T_RemType, MSF_TYPE }, { "msg", 3, T_RemType, MSG_TYPE }, { "november", 3, T_Month, 10 }, { "october", 3, T_Month, 9 }, { "omit", 3, T_Omit, 0 }, { "omitfunc", 8, T_OmitFunc, 0 }, { "once", 3, T_Once, 0 }, { "pop-omit-context", 3, T_Pop, 0 }, { "preserve", 8, T_Preserve, 0 }, { "priority", 8, T_Priority, 0 }, { "ps", 2, T_RemType, PS_TYPE }, { "psfile", 6, T_RemType, PSF_TYPE }, { "push-omit-context", 4, T_Push, 0 }, { "rem", 3, T_Rem, 0 }, { "run", 3, T_RemType, RUN_TYPE }, { "satisfy", 7, T_RemType, SAT_TYPE }, { "saturday", 3, T_WkDay, 5 }, { "scanfrom", 4, T_Scanfrom, SCANFROM_TYPE }, { "sched", 5, T_Sched, 0 }, { "september", 3, T_Month, 8 }, { "set", 3, T_Set, 0 }, { "skip", 3, T_Skip, SKIP_SKIP }, { "special", 7, T_RemType, PASSTHRU_TYPE }, { "sunday", 3, T_WkDay, 6 }, { "tag", 3, T_Tag, 0 }, { "through", 7, T_Through, 0 }, { "thursday", 3, T_WkDay, 3 }, { "tuesday", 3, T_WkDay, 1 }, { "unset", 5, T_UnSet, 0 }, { "until", 3, T_Until, 0 }, { "warn", 4, T_Warn, 0 }, { "wednesday", 3, T_WkDay, 2 } }; /* If language != English, we must also search the following... */ #if LANG != ENGLISH Token NonEnglishToks[] = { /* NAME MINLEN TYPE VALUE */ { L_MONDAY, 3, T_WkDay, 0 }, { L_TUESDAY, 3, T_WkDay, 1 }, { L_WEDNESDAY, 3, T_WkDay, 2 }, { L_THURSDAY, 3, T_WkDay, 3 }, { L_FRIDAY, 3, T_WkDay, 4 }, { L_SATURDAY, 3, T_WkDay, 5 }, { L_SUNDAY, 3, T_WkDay, 6 }, { L_JAN, 3, T_Month, 0 }, { L_FEB, 3, T_Month, 1 }, { L_MAR, 3, T_Month, 2 }, { L_APR, 3, T_Month, 3 }, { L_MAY, 3, T_Month, 4 }, { L_JUN, 3, T_Month, 5 }, { L_JUL, 3, T_Month, 6 }, { L_AUG, 3, T_Month, 7 }, { L_SEP, 3, T_Month, 8 }, { L_OCT, 3, T_Month, 9 }, { L_NOV, 3, T_Month, 10 }, { L_DEC, 3, T_Month, 11 } }; #endif static int TokStrCmp (Token const *t, char const *s); /***************************************************************/ /* */ /* FindInitialToken */ /* */ /* Find the initial token on the command line. If it's a */ /* left square bracket, return a T_Illegal type. */ /* */ /***************************************************************/ char const *FindInitialToken(Token *tok, char const *s) { DynamicBuffer buf; DBufInit(&buf); tok->type = T_Illegal; while (isempty(*s)) s++; while (*s && !isempty(*s)) { if (DBufPutc(&buf, *s++) != OK) return s; } FindToken(DBufValue(&buf), tok); DBufFree(&buf); return s; } /***************************************************************/ /* */ /* FindToken */ /* */ /* Given a string, which token is it? */ /* */ /***************************************************************/ void FindToken(char const *s, Token *tok) { int top, bot, mid, r, max; int l; tok->type = T_Illegal; if (! *s) { tok->type = T_Empty; return; } if (*s == '#' || *s == ';') { tok->type = T_Comment; return; } /* Quickly give up the search if first char not a letter */ if ( ! isalpha(*s)) { FindNumericToken(s, tok); return; } l = strlen(s); /* Ignore trailing commas */ if (l > 0 && s[l-1] == ',') { l--; } bot = 0; top = sizeof(TokArray) / sizeof(TokArray[0]) - 1; max = sizeof(TokArray) / sizeof(TokArray[0]); while(top >= bot) { mid = (top + bot) / 2; r = TokStrCmp(&TokArray[mid], s); if (!r) { if (l >= TokArray[mid].MinLen) { tok->type = TokArray[mid].type; tok->val = TokArray[mid].val; return; } else { while (mid && !TokStrCmp(&TokArray[mid-1],s)) mid--; while (mid < max && !TokStrCmp(&TokArray[mid], s) && l < TokArray[mid].MinLen) { mid++; } if (mid < max && !TokStrCmp(&TokArray[mid], s)) { tok->type = TokArray[mid].type; tok->val = TokArray[mid].val; return; } } break; } if (r > 0) top = mid-1; else bot=mid+1; } /* If language is other than English, search the DayNames[] and MonthNames[] array. */ #if LANG != ENGLISH for (r=0; r<(sizeof(NonEnglishToks) / sizeof(Token)); r++) { if (l >= NonEnglishToks[r].MinLen && !TokStrCmp(&NonEnglishToks[r], s)) { tok->type = NonEnglishToks[r].type; tok->val = NonEnglishToks[r].val; return; } } #endif return; } /***************************************************************/ /* */ /* FindNumericToken */ /* */ /* Parse a numeric token: */ /* Year - number between 1990 and 2085, or 90-99. */ /* Day - number between 1 and 31 */ /* Delta - +[+]n */ /* Back - -[-]n */ /* Rep - *n */ /* */ /***************************************************************/ void FindNumericToken(char const *s, Token *t) { int mult = 1, hour, min; char const *s_orig = s; t->type = T_Illegal; t->val = 0; if (isdigit(*s)) { PARSENUM(t->val, s); /* If we hit a '-' or a '/', we may have a date or a datetime */ if (*s == '-' || *s == '/') { char const *p = s_orig; int jul, tim; if (ParseLiteralDate(&p, &jul, &tim) == OK) { if (*p) return; if (tim == NO_TIME) { t->type = T_Date; t->val = jul; return; } t->type = T_DateTime; t->val = MINUTES_PER_DAY * jul + tim; } return; } /* If we hit a comma, swallow it. This allows stuff like Jan 6, 1998 */ if (*s == ',') { s++; /* Special hack - convert years between 90 and 99 to 1990 and 1999 */ if (t->val >= 90 && t->val <= 99) t->val += 1900; /* Classify the number we've got */ if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year; else if (t->val >= 1 && t->val <= 31) t->type = T_Day; else t->type = T_Number; return; } /* If we hit a colon or a period, we've probably got a time hr:min */ if (*s == ':' || *s == '.' || *s == TimeSep) { s++; hour = t->val; PARSENUM(min, s); if (*s || min > 59) return; /* Illegal time */ t->val = hour*60 + min; /* Convert to minutes past midnight */ if (hour <= 23) { t->type = T_Time; } else { t->type = T_LongTime; } return; } /* If we hit a non-digit, error! */ if (*s) return; /* Special hack - convert years between 90 and 99 to 1990 and 1999 */ if (t->val >= 90 && t->val <= 99) t->val += 1900; /* Classify the number we've got */ if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year; else if (t->val >= 1 && t->val <= 31) t->type = T_Day; else t->type = T_Number; return; } else if (*s == '*') { s++; PARSENUM(t->val, s); if (*s) return; /* Illegal token if followed by non-numeric char */ t->type = T_Rep; return; } else if (*s == '+') { s++; if (*s == '+') { mult = -1; s++; } PARSENUM(t->val, s); if (*s) return; /* Illegal token if followed by non-numeric char */ t->type = T_Delta; t->val *= mult; return; } else if (*s == '-') { s++; if (*s == '-') { mult = -1; s++; } PARSENUM(t->val, s); if (*s) return; /* Illegal token if followed by non-numeric char */ t->type = T_Back; t->val *= mult; return; } return; /* Unknown token type */ } /***************************************************************/ /* */ /* TokStrCmp */ /* */ /* Compare a token to a string. */ /* */ /***************************************************************/ static int TokStrCmp(Token const *t, char const *s) { register int r; char const *tk = t->name; while(*tk && *s && !(*s == ',' && *(s+1) == 0)) { r = tolower(*tk) - tolower(*s); tk++; s++; if (r) return r; } /* Ignore trailing commas on s */ if (!*s || (*s == ',' && !*(s+1))) return 0; return (tolower(*tk) - tolower(*s)); } remind-03.01.15/src/trigger.c0000644000076400007640000003442512514120466013750 0ustar dfsdfs/***************************************************************/ /* */ /* TRIGGER.C */ /* */ /* Routines for figuring out the trigger date of a reminder */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include "types.h" #include "expr.h" #include "protos.h" #include "globals.h" #include "err.h" #define GOT_DAY 1 #define GOT_MON 2 #define GOT_YR 4 #define GOT_WD 8 static int JYear(int jul); static int JMonth(int jul); static int NextSimpleTrig(int startdate, Trigger *trig, int *err); static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart); /***************************************************************/ /* */ /* NextSimpleTrig */ /* */ /* Compute the "simple" trigger date, taking into account */ /* ONLY the day of week, day, month and year components. */ /* Normally, returns -1 if the trigger has expired. As a */ /* special case, if D, M, Y [WD] are specified, returns the */ /* Julian date, regardless of whether it's expired. This is */ /* so that dates with a REP can be handled properly. */ /* */ /***************************************************************/ static int NextSimpleTrig(int startdate, Trigger *trig, int *err) { int typ = 0; int d, m, y, j, d2, m2, y2; *err = 0; FromJulian(startdate, &y, &m, &d); d2 = d; m2 = m; y2 = y; if (trig->d != NO_DAY) typ |= GOT_DAY; if (trig->m != NO_MON) typ |= GOT_MON; if (trig->y != NO_YR) typ |= GOT_YR; if (trig->wd != NO_WD) typ |= GOT_WD; switch(typ) { case 0: case GOT_WD: if (trig->wd != NO_WD) while(! (trig->wd & (1 << (startdate%7)))) startdate++; return startdate; case GOT_DAY: if (d > trig->d) { m++; if (m == 12) { m = 0; y++; } } while (trig->d > DaysInMonth(m, trig->y)) m++; j = Julian(y, m, trig->d); return j; case GOT_MON: if (m == trig->m) return startdate; else if (m > trig->m) return Julian(y+1, trig->m, 1); else return Julian(y, trig->m, 1); case GOT_YR: if (y == trig->y) return startdate; else if (y < trig->y) return Julian(trig->y, 0, 1); else return -1; case GOT_DAY+GOT_MON: if (m > trig->m || (m == trig->m && d > trig->d)) y++; if (trig->d > MonthDays[trig->m]) { *err = E_BAD_DATE; return -1; } /* Take care of Feb. 29 */ while (trig->d > DaysInMonth(trig->m, y)) y++; return Julian(y, trig->m, trig->d); case GOT_DAY+GOT_YR: if (y < trig->y) return Julian(trig->y, 0, trig->d); else if (y > trig->y) return -1; if (d > trig->d) { m++; if (m == 12) return -1; } while (trig->d > DaysInMonth(m, trig->y)) m++; return Julian(trig->y, m, trig->d); case GOT_MON+GOT_YR: if (y > trig->y || (y == trig->y && m > trig->m)) return -1; if (y < trig->y) return Julian(trig->y, trig->m, 1); if (m == trig->m) return startdate; return Julian(trig->y, trig->m, 1); case GOT_DAY+GOT_MON+GOT_YR: if (trig->d > DaysInMonth(trig->m, trig->y)) { *err = E_BAD_DATE; return -1; } return Julian(trig->y, trig->m, trig->d); case GOT_YR+GOT_WD: if (y > trig->y) return -1; if (y < trig->y) j = Julian(trig->y, 0, 1); else j = startdate; while(! (trig->wd & (1 << (j%7)))) j++; if (JYear(j) > trig->y) return -1; return j; case GOT_MON+GOT_WD: if (m == trig->m) { j = startdate; while(! (trig->wd & (1 << (j%7)))) j++; if (JMonth(j) == trig->m) return j; } if (m >= trig->m) j = Julian(y+1, trig->m, 1); else j = Julian(y, trig->m, 1); while(! (trig->wd & (1 << (j%7)))) j++; return j; /* Guaranteed to be within the month */ case GOT_DAY+GOT_WD: if (m !=0 || y > BASE) { m2 = m-1; if (m2 < 0) { y2 = y-1; m2 = 11; } /* If there are fewer days in previous month, no match */ if (trig->d <= DaysInMonth(m2, y2)) { j = Julian(y2, m2, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } } /* Try this month */ if (trig->d <= DaysInMonth(m, y)) { j = Julian(y, m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } /* Argh! Try next avail. month */ m2 = m+1; if (m2 > 11) { m2 = 0; y++; } while (trig->d > DaysInMonth(m2, y)) m2++; j = Julian(y, m2, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; case GOT_WD+GOT_YR+GOT_DAY: if (y > trig->y+1 || (y > trig->y && m>0)) return -1; if (y > trig->y) { j = Julian(trig->y, 11, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } else if (y < trig->y) { j = Julian(trig->y, 0, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; } else { /* Try last month */ if (m > 0) { m2 = m-1; while (trig->d > DaysInMonth(m2, trig->y)) m2--; j = Julian(trig->y, m2, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } } /* Try this month */ if (trig->d <= DaysInMonth(m, trig->y)) { j = Julian(trig->y, m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } /* Must be next month */ if (m == 11) return -1; m++; while (trig->d > DaysInMonth(m, trig->d)) m++; j = Julian(trig->y, m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; case GOT_DAY+GOT_MON+GOT_WD: if (trig->d > MonthDays[trig->m]) { *err = E_BAD_DATE; return -1; } /* Back up a year in case we'll cross a year boundary*/ if (y > BASE) { y--; } /* Move up to the first valid year */ while (trig->d > DaysInMonth(trig->m, y)) y++; /* Try last year */ j = Julian(y, trig->m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; /* Try this year */ y++; j = Julian(y, trig->m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; /* Must be next year */ y++; while (trig->d > DaysInMonth(trig->m, y)) y++; j = Julian(y, trig->m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; case GOT_WD+GOT_MON+GOT_YR: if (y > trig->y || (y == trig->y && m > trig->m)) return -1; if (trig->y > y || (trig->y == y && trig->m > m)) { j = Julian(trig->y, trig->m, 1); while(! (trig->wd & (1 << (j%7)))) j++; return j; } else { j = startdate; while(! (trig->wd & (1 << (j%7)))) j++; FromJulian(j, &y2, &m2, &d2); if (m2 == trig->m) return j; else return -1; } case GOT_WD+GOT_DAY+GOT_MON+GOT_YR: if (trig->d > DaysInMonth(trig->m, trig->y)) { *err = E_BAD_DATE; return -1; } j = Julian(trig->y, trig->m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; default: Eprint("NextSimpleTrig %s %d", ErrMsg[E_SWERR], typ); *err = E_SWERR; return -1; } } /***************************************************************/ /* */ /* JMonth - Given a Julian date, what's the month? */ /* */ /***************************************************************/ static int JMonth(int jul) { int y, m, d; FromJulian(jul, &y, &m, &d); return m; } /***************************************************************/ /* */ /* JYear - Given a Julian date, what's the year? */ /* */ /***************************************************************/ static int JYear(int jul) { int y, m, d; FromJulian(jul, &y, &m, &d); return y; } /***************************************************************/ /* */ /* GetNextTriggerDate */ /* */ /* Given a trigger, compute the next trigger date. */ /* */ /* Returns the Julian date of next trigger, -1 if */ /* expired, -2 if can't compute trigger date. */ /* */ /***************************************************************/ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart) { int simple, mod, omit; /* First: Have we passed the UNTIL date? */ if (trig->until != NO_UNTIL && trig->until < start) { trig->expired = 1; return -1; /* expired */ } /* Next: If it's an "AFTER"-type skip, back up until we're at the start of a block of holidays */ if (trig->skip == AFTER_SKIP) { int iter = 0; while (iter++ <= MaxSatIter) { *err = IsOmitted(start-1, trig->localomit, trig->omitfunc, &omit); if (*err) return -2; if (!omit) { break; } start--; } if (iter > MaxSatIter) { /* omitfunc must have returned "true" too often */ *err = E_CANT_TRIG; return -2; } } /* Find the next simple trigger */ simple = NextSimpleTrig(start, trig, err); /* Problems? */ if (*err || (simple == -1)) return -1; /* Suggested starting point for next attempt */ *nextstart = simple+1; /* If there's a BACK, back up... */ if (trig->back != NO_BACK) { mod = trig->back; if (mod < 0) { simple += mod; } else { int iter = 0; int max = MaxSatIter; if (max < mod*2) { max = mod*2; } while(iter++ <= max) { if (!mod) { break; } simple--; *err = IsOmitted(simple, trig->localomit, trig->omitfunc, &omit); if (*err) return -2; if (!omit) mod--; } if (iter > max) { *err = E_CANT_TRIG; return -2; } } } /* If there's a REP, calculate the next occurrence */ if (trig->rep != NO_REP) { if (simple < start) { mod = (start - simple) / trig->rep; simple = simple + mod * trig->rep; if (simple < start) simple += trig->rep; } } /* If it's a "BEFORE"-type skip, back up */ if (trig->skip == BEFORE_SKIP) { int iter = 0; while(iter++ <= MaxSatIter) { *err = IsOmitted(simple, trig->localomit, trig->omitfunc, &omit); if (*err) return -2; if (!omit) { break; } simple--; } if (iter > MaxSatIter) { *err = E_CANT_TRIG; return -2; } } /* If it's an "AFTER"-type skip, jump ahead */ if (trig->skip == AFTER_SKIP) { int iter = 0; while (iter++ <= MaxSatIter) { *err = IsOmitted(simple, trig->localomit, trig->omitfunc, &omit); if (*err) return -2; if (!omit) { break; } simple++; } if (iter > MaxSatIter) { *err = E_CANT_TRIG; return -2; } } /* Return the date */ return simple; } /***************************************************************/ /* */ /* ComputeTrigger */ /* */ /* The main function. Compute the next trigger date given */ /* today's date. */ /* */ /***************************************************************/ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals) { int nattempts = 0, start = today, nextstart = 0, y, m, d, omit, result; trig->expired = 0; if (save_in_globals) { LastTrigValid = 0; } /* Assume everything works */ *err = OK; /* But check for obvious problems... */ if (trig->localomit == 1 + 2 + 4 + 8 + 16 + 32 + 64) { *err = E_2MANY_LOCALOMIT; return -1; } if (trig->rep != NO_REP && (trig->d == NO_DAY || trig->m == NO_MON || trig->y == NO_YR)) { Eprint("%s", ErrMsg[E_REP_FULSPEC]); *err = E_REP_FULSPEC; return -1; } while (nattempts++ < TRIG_ATTEMPTS) { result = GetNextTriggerDate(trig, start, err, &nextstart); /* If there's an error, die immediately */ if (*err) return -1; if (result == -1) { trig->expired = 1; if (DebugFlag & DB_PRTTRIG) { fprintf(ErrFp, "%s(%d): %s\n", FileName, LineNo, ErrMsg[E_EXPIRED]); } return -1; } /* If result is >= today, great! */ if (trig->skip == SKIP_SKIP) { *err = IsOmitted(result, trig->localomit, trig->omitfunc, &omit); if (*err) return -1; } else { omit = 0; } if (result >= today && (trig->skip != SKIP_SKIP || !omit)) { if (save_in_globals) { LastTriggerDate = result; /* Save in global var */ LastTrigValid = 1; } if (DebugFlag & DB_PRTTRIG) { FromJulian(result, &y, &m, &d); fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d\n", FileName, LineNo, DayName[result % 7], d, MonthName[m], y); } return result; } /* If it's a simple trigger, no point in rescanning */ if (trig->back == NO_BACK && trig->skip == NO_SKIP && trig->rep == NO_REP) { trig->expired = 1; if (DebugFlag & DB_PRTTRIG) { fprintf(ErrFp, "%s(%d): %s\n", FileName, LineNo, ErrMsg[E_EXPIRED]); } if (result != -1) { if (save_in_globals) { LastTriggerDate = result; LastTrigValid = 1; } } return -1; } if (trig->skip == SKIP_SKIP && omit && nextstart <= start && result >= start) { nextstart = result + 1; } /* Keep scanning... unless there's no point in doing it.*/ if (nextstart <= start) { if (result != -1) { if (save_in_globals) { LastTriggerDate = result; LastTrigValid = 1; } } trig->expired = 1; if (DebugFlag & DB_PRTTRIG) { fprintf(ErrFp, "%s(%d): %s\n", FileName, LineNo, ErrMsg[E_EXPIRED]); } return -1; } else start = nextstart; } /* We failed - too many attempts or trigger has expired*/ *err = E_CANT_TRIG; return -1; } remind-03.01.15/src/types.h0000644000076400007640000001203712514120463013446 0ustar dfsdfs/***************************************************************/ /* */ /* TYPES.H */ /* */ /* Type definitions all dumped here. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include #include "dynbuf.h" /* Values */ typedef struct { char type; union { char *str; int val; } v; } Value; /* Define the type of operators */ typedef struct { char const *name; char prec; char type; int (*func)(void); } Operator; /* Structure for passing in Nargs and out RetVal from functions */ typedef struct { int nargs; Value retval; } func_info; /* Define the type of user-functions */ typedef struct { char const *name; char minargs; char maxargs; char is_constant; int (*func)(func_info *); } BuiltinFunc; /* Define the structure of a variable */ typedef struct var { struct var *next; char name[VAR_NAME_LEN+1]; char preserve; Value v; } Var; /* A trigger */ typedef struct { int expired; int wd; int d; int m; int y; int back; int delta; int rep; int localomit; int skip; int until; int typ; int once; int scanfrom; int priority; char sched[VAR_NAME_LEN+1]; /* Scheduling function */ char warn[VAR_NAME_LEN+1]; /* Warning function */ char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */ DynamicBuffer tags; char passthru[PASSTHRU_LEN+1]; } Trigger; /* A time trigger */ typedef struct { int ttime; int nexttime; int delta; int rep; int duration; } TimeTrig; /* The parse pointer */ typedef struct { char isnested; /* Is it a nested expression? */ char allownested; char const *text; /* Start of text */ char const *pos; /* Current position */ char const *etext; /* Substituted text */ char const *epos; /* Position in substituted text */ DynamicBuffer pushedToken; /* Pushed-back token */ char const *tokenPushed; /* NULL if no pushed-back token */ char expr_happened; /* Did we encounter an [expression] ? */ char nonconst_expr; /* Did we encounter a non-constant [expression] ? */ } Parser; typedef Parser *ParsePtr; /* Pointer to parser structure */ /* Some useful manifest constants */ #define NO_BACK 0 #define NO_DELTA 0 #define NO_REP 0 #define NO_WD 0 #define NO_DAY -1 #define NO_MON -1 #define NO_YR -1 #define NO_UNTIL -1 #define NO_ONCE 0 #define ONCE_ONCE 1 #define NO_DATE -1 #define NO_SKIP 0 #define SKIP_SKIP 1 #define BEFORE_SKIP 2 #define AFTER_SKIP 3 #define NO_TIME INT_MAX #define NO_PRIORITY 5000 /* Default priority is midway between 0 and 9999 */ #define NO_TYPE 0 #define MSG_TYPE 1 #define RUN_TYPE 2 #define CAL_TYPE 3 #define SAT_TYPE 4 #define PS_TYPE 5 #define PSF_TYPE 6 #define MSF_TYPE 7 #define PASSTHRU_TYPE 8 /* DEFINES for debugging flags */ #define DB_PRTLINE 1 #define DB_PRTEXPR 2 #define DB_PRTTRIG 4 #define DB_DUMP_VARS 8 #define DB_ECHO_LINE 16 #define DB_TRACE_FILES 32 /* Enumeration of the tokens */ enum TokTypes { T_Illegal, /* Commands first */ T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_If, T_Else, T_EndIf, T_IfTrig, T_ErrMsg, T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit, T_WkDay, T_Month, T_Time, T_Date, T_DateTime, T_Skip, T_At, T_RemType, T_Until, T_Year, T_Day, T_Rep, T_Delta, T_Back, T_Once, T_Empty, T_Comment, T_Number, T_Clr, T_Debug, T_Dumpvars, T_Scanfrom, T_Flush, T_Priority, T_Sched, T_Warn, T_Tag, T_Duration, T_LongTime, T_OmitFunc, T_Through }; /* The structure of a token */ typedef struct { char *name; char MinLen; enum TokTypes type; int val; } Token; /* Flags for the state of the "if" stack */ #define IF_TRUE 0 #define IF_FALSE 1 #define BEFORE_ELSE 0 #define AFTER_ELSE 2 #define IF_MASK 3 #define IF_TRUE_MASK 1 #define IF_ELSE_MASK 2 /* Flags for the DoSubst function */ #define NORMAL_MODE 0 #define CAL_MODE 1 #define ADVANCE_MODE 2 #define QUOTE_MARKER 1 /* Unlikely character to appear in reminder */ /* Flags for disabling run */ #define RUN_CMDLINE 1 #define RUN_SCRIPT 2 #define RUN_NOTOWNER 4 /* Flags for the SimpleCalendar format */ #define SC_AMPM 0 /* Time shown as 3:00am, etc. */ #define SC_MIL 1 /* 24-hour time format */ #define SC_NOTIME 2 /* Do not display time in SC format. */ /* Flags for sorting */ #define SORT_NONE 0 #define SORT_ASCEND 1 #define SORT_DESCEND 2 /* Flags for FROM / SCANFROM */ #define SCANFROM_TYPE 0 #define FROM_TYPE 1 remind-03.01.15/src/userfns.c0000644000076400007640000002622112514120460013757 0ustar dfsdfs/***************************************************************/ /* */ /* USERFNS.C */ /* */ /* This file contains the routines to support user-defined */ /* functions. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include "types.h" #include "globals.h" #include "protos.h" #include "err.h" #include "expr.h" #define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */ /* Define the data structure used to hold a user-defined function */ typedef struct udf_struct { struct udf_struct *next; char name[VAR_NAME_LEN+1]; char const *text; Var *locals; char IsActive; int nargs; } UserFunc; /* The hash table */ static UserFunc *FuncHash[FUNC_HASH_SIZE]; /* Access to built-in functions */ extern int NumFuncs; extern BuiltinFunc Func[]; /* We need access to the expression evaluation stack */ extern Value ValStack[]; extern int ValStackPtr; static void DestroyUserFunc (UserFunc *f); static void FUnset (char const *name); static void FSet (UserFunc *f); static int SetUpLocalVars (UserFunc *f); static void DestroyLocalVals (UserFunc *f); /***************************************************************/ /* */ /* DoFset */ /* */ /* Define a user-defined function - the FSET command. */ /* */ /***************************************************************/ int DoFset(ParsePtr p) { int r; int c; UserFunc *func; Var *v; DynamicBuffer buf; DBufInit(&buf); /* Get the function name */ if ( (r=ParseIdentifier(p, &buf)) ) return r; if (*DBufValue(&buf) == '$') { DBufFree(&buf); return E_BAD_ID; } /* Should be followed by '(' */ c = ParseNonSpaceChar(p, &r, 0); if (r) { DBufFree(&buf); return r; } if (c != '(') { DBufFree(&buf); return E_PARSE_ERR; } func = NEW(UserFunc); if (!func) { DBufFree(&buf); return E_NO_MEM; } StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN); DBufFree(&buf); if (!Hush) { if (FindFunc(DBufValue(&buf), Func, NumFuncs)) { Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], DBufValue(&buf)); } } func->locals = NULL; func->text = NULL; func->IsActive = 0; func->nargs = 0; /* Get the local variables - we insert the local variables in REVERSE order, but that's OK, because we pop them off the stack in reverse order, too, so everything works out just fine. */ c=ParseNonSpaceChar(p, &r, 1); if (r) return r; if (c == ')') { (void) ParseNonSpaceChar(p, &r, 0); } else { while(1) { if ( (r=ParseIdentifier(p, &buf)) ) return r; if (*DBufValue(&buf) == '$') { DBufFree(&buf); return E_BAD_ID; } v = NEW(Var); if (!v) { DBufFree(&buf); DestroyUserFunc(func); return E_NO_MEM; } func->nargs++; v->v.type = ERR_TYPE; StrnCpy(v->name, DBufValue(&buf), VAR_NAME_LEN); DBufFree(&buf); v->next = func->locals; func->locals = v; c = ParseNonSpaceChar(p, &r, 0); if (c == ')') break; else if (c != ',') { DestroyUserFunc(func); return E_PARSE_ERR; } } } /* Allow an optional = sign: FSET f(x) = x*x */ c = ParseNonSpaceChar(p, &r, 1); if (c == '=') { c = ParseNonSpaceChar(p, &r, 0); } /* Copy the text over */ if (p->isnested) { Eprint("%s", ErrMsg[E_CANTNEST_FDEF]); DestroyUserFunc(func); return E_PARSE_ERR; } func->text = StrDup(p->pos); if (!func->text) { DestroyUserFunc(func); return E_NO_MEM; } /* If an old definition of this function exists, destroy it */ FUnset(func->name); /* Add the function definition */ FSet(func); return OK; } /***************************************************************/ /* */ /* DestroyUserFunc */ /* */ /* Free up all the resources used by a user-defined function. */ /* */ /***************************************************************/ static void DestroyUserFunc(UserFunc *f) { Var *v, *prev; /* Free the local variables first */ v = f->locals; while(v) { DestroyValue(v->v); prev = v; v = v->next; free(prev); } /* Free the function definition */ if (f->text) free( (char *) f->text); /* Free the data structure itself */ free(f); } /***************************************************************/ /* */ /* FUnset */ /* */ /* Delete the function definition with the given name, if */ /* it exists. */ /* */ /***************************************************************/ static void FUnset(char const *name) { UserFunc *cur, *prev; int h; h = HashVal(name) % FUNC_HASH_SIZE; cur = FuncHash[h]; prev = NULL; while(cur) { if (! StrinCmp(name, cur->name, VAR_NAME_LEN)) break; prev = cur; cur = cur->next; } if (!cur) return; if (prev) prev->next = cur->next; else FuncHash[h] = cur->next; DestroyUserFunc(cur); } /***************************************************************/ /* */ /* FSet */ /* */ /* Insert a user-defined function into the hash table. */ /* */ /***************************************************************/ static void FSet(UserFunc *f) { int h = HashVal(f->name) % FUNC_HASH_SIZE; f->next = FuncHash[h]; FuncHash[h] = f; } /***************************************************************/ /* */ /* CallUserFunc */ /* */ /* Call a user-defined function. */ /* */ /***************************************************************/ int CallUserFunc(char const *name, int nargs, ParsePtr p) { UserFunc *f; int h = HashVal(name) % FUNC_HASH_SIZE; int i; char const *s; /* Search for the function */ f = FuncHash[h]; while (f && StrinCmp(name, f->name, VAR_NAME_LEN)) f = f->next; if (!f) { Eprint("%s: `%s'", ErrMsg[E_UNDEF_FUNC], name); return E_UNDEF_FUNC; } /* Debugging stuff */ if (DebugFlag & DB_PRTEXPR) { fprintf(ErrFp, "%s %s(", ErrMsg[E_ENTER_FUN], f->name); for (i=0; iIsActive) { if (DebugFlag &DB_PRTEXPR) { fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name); fprintf(ErrFp, "%s\n", ErrMsg[E_RECURSIVE]); } return E_RECURSIVE; } /* Check number of args */ if (nargs != f->nargs) { if (DebugFlag &DB_PRTEXPR) { fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name); fprintf(ErrFp, "%s\n", ErrMsg[(nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS]); } return (nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS; } /* Found the function - set up a local variable frame */ h = SetUpLocalVars(f); if (h) { if (DebugFlag &DB_PRTEXPR) { fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name); fprintf(ErrFp, "%s\n", ErrMsg[h]); } return h; } /* Evaluate the expression */ f->IsActive = 1; s = f->text; /* Skip the opening bracket, if there's one */ while (isempty(*s)) s++; if (*s == BEG_OF_EXPR) s++; h = Evaluate(&s, f->locals, p); f->IsActive = 0; DestroyLocalVals(f); if (DebugFlag &DB_PRTEXPR) { fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name); if (h) fprintf(ErrFp, "%s\n", ErrMsg[h]); else { PrintValue(&ValStack[ValStackPtr-1], ErrFp); fprintf(ErrFp, "\n"); } } return h; } /***************************************************************/ /* */ /* SetUpLocalVars */ /* */ /* Set up the local variables from the stack frame. */ /* */ /***************************************************************/ static int SetUpLocalVars(UserFunc *f) { int i, r; Var *var; for (i=0, var=f->locals; var && inargs; var=var->next, i++) { if ( (r=FnPopValStack(&(var->v))) ) { DestroyLocalVals(f); return r; } } return OK; } /***************************************************************/ /* */ /* DestroyLocalVals */ /* */ /* Destroy the values of all local variables after evaluating */ /* the function. */ /* */ /***************************************************************/ static void DestroyLocalVals(UserFunc *f) { Var *v = f->locals; while(v) { DestroyValue(v->v); v = v->next; } } /***************************************************************/ /* */ /* UserFuncExists */ /* */ /* Return the number of arguments accepted by the function if */ /* it is defined, or -1 if it is not defined. */ /* */ /***************************************************************/ int UserFuncExists(char const *fn) { UserFunc *f; int h = HashVal(fn) % FUNC_HASH_SIZE; f = FuncHash[h]; while (f && StrinCmp(fn, f->name, VAR_NAME_LEN)) f = f->next; if (!f) return -1; else return f->nargs; } remind-03.01.15/src/utils.c0000644000076400007640000001127212514120447013437 0ustar dfsdfs/***************************************************************/ /* */ /* UTILS.C */ /* */ /* Useful utility functions. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #include "types.h" #include "globals.h" #include "protos.h" #define UPPER(c) toupper(c) /***************************************************************/ /* */ /* StrnCpy */ /* */ /* Just like strncpy EXCEPT we ALWAYS copy the trailing 0. */ /* */ /***************************************************************/ char *StrnCpy(char *dest, char const *source, int n) { char *odest = dest; while (n-- && (*dest++ = *source++)) ; if (*(dest-1)) *dest = 0; return odest; } /***************************************************************/ /* */ /* StrMatch */ /* */ /* Checks that two strings match (case-insensitive) to at */ /* least the specified number of characters, or the length */ /* of the first string, whichever is greater. */ /* */ /***************************************************************/ int StrMatch(char const *s1, char const *s2, int n) { int l; if ((l = strlen(s1)) < n) return 0; return !StrinCmp(s1, s2, l); } /***************************************************************/ /* */ /* StrinCmp - compare strings, case-insensitive */ /* */ /***************************************************************/ int StrinCmp(char const *s1, char const *s2, int n) { register int r; while (n && *s1 && *s2) { n--; r = UPPER(*s1) - UPPER(*s2); if (r) return r; s1++; s2++; } if (n) return (UPPER(*s1) - UPPER(*s2)); else return 0; } /***************************************************************/ /* */ /* StrDup */ /* */ /* Like ANSI strdup */ /* */ /***************************************************************/ char *StrDup(char const *s) { char *ret = malloc(strlen(s)+1); if (!ret) return NULL; strcpy(ret, s); return ret; } /***************************************************************/ /* */ /* StrCmpi */ /* */ /* Compare strings, case insensitive. */ /* */ /***************************************************************/ int StrCmpi(char const *s1, char const *s2) { int r; while (*s1 && *s2) { r = UPPER(*s1) - UPPER(*s2); if (r) return r; s1++; s2++; } return UPPER(*s1) - UPPER(*s2); } /***************************************************************/ /* */ /* DateOK */ /* */ /* Return 1 if the date is OK, 0 otherwise. */ /* */ /***************************************************************/ int DateOK(int y, int m, int d) { if (d < 1 || m < 0 || y < BASE || m > 11 || y > BASE + YR_RANGE || d > DaysInMonth(m, y) ) return 0; else return 1; } remind-03.01.15/src/var.c0000644000076400007640000006201612555464051013100 0ustar dfsdfs/***************************************************************/ /* */ /* VAR.C */ /* */ /* This file contains routines, structures, etc for */ /* user- and system-defined variables. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-1998 by Dianne Skoll */ /* Copyright (C) 1999-2007 by Roaring Penguin Software Inc. */ /* */ /***************************************************************/ #include "config.h" #include #include #include #include #include "types.h" #include "expr.h" #include "globals.h" #include "protos.h" #include "err.h" #define UPPER(c) (islower(c) ? toupper(c) : c) /* The variable hash table */ #define VAR_HASH_SIZE 64 #define VARIABLE ErrMsg[E_VAR] #define VALUE ErrMsg[E_VAL] #define UNDEF ErrMsg[E_UNDEF] static Var *VHashTbl[VAR_HASH_SIZE]; typedef int (*SysVarFunc)(int, Value *); static int trig_date_func(int do_set, Value *val) { val->type = DATE_TYPE; if (!LastTrigValid) { val->v.val = 0; } else { val->v.val = LastTriggerDate; } return OK; } static int trig_day_func(int do_set, Value *val) { int y, m, d; val->type = INT_TYPE; if (!LastTrigValid) { val->v.val = -1; return OK; } FromJulian(LastTriggerDate, &y, &m, &d); val->v.val = d; return OK; } static int trig_mon_func(int do_set, Value *val) { int y, m, d; val->type = INT_TYPE; if (!LastTrigValid) { val->v.val = -1; return OK; } FromJulian(LastTriggerDate, &y, &m, &d); val->v.val = m+1; return OK; } static int trig_year_func(int do_set, Value *val) { int y, m, d; val->type = INT_TYPE; if (!LastTrigValid) { val->v.val = -1; return OK; } FromJulian(LastTriggerDate, &y, &m, &d); val->v.val = y; return OK; } static int trig_wday_func(int do_set, Value *val) { val->type = INT_TYPE; if (!LastTrigValid) { val->v.val = -1; return OK; } val->v.val = (LastTriggerDate + 1) % 7; return OK; } static int today_date_func(int do_set, Value *val) { val->type = DATE_TYPE; val->v.val = JulianToday; return OK; } static int today_day_func(int do_set, Value *val) { int y, m, d; val->type = INT_TYPE; FromJulian(JulianToday, &y, &m, &d); val->v.val = d; return OK; } static int today_mon_func(int do_set, Value *val) { int y, m, d; val->type = INT_TYPE; FromJulian(JulianToday, &y, &m, &d); val->v.val = m+1; return OK; } static int today_year_func(int do_set, Value *val) { int y, m, d; val->type = INT_TYPE; FromJulian(JulianToday, &y, &m, &d); val->v.val = y; return OK; } static int today_wday_func(int do_set, Value *val) { val->type = INT_TYPE; val->v.val = (JulianToday + 1) % 7; return OK; } static int date_sep_func(int do_set, Value *val) { if (!do_set) { val->v.str = malloc(2); if (!val->v.str) return E_NO_MEM; val->v.str[0] = DateSep; val->v.str[1] = 0; val->type = STR_TYPE; return OK; } if (val->type != STR_TYPE) return E_BAD_TYPE; if (strcmp(val->v.str, "/") && strcmp(val->v.str, "-")) { return E_BAD_TYPE; } DateSep = val->v.str[0]; return OK; } static int time_sep_func(int do_set, Value *val) { if (!do_set) { val->v.str = malloc(2); if (!val->v.str) return E_NO_MEM; val->v.str[0] = TimeSep; val->v.str[1] = 0; val->type = STR_TYPE; return OK; } if (val->type != STR_TYPE) return E_BAD_TYPE; if (strcmp(val->v.str, ":") && strcmp(val->v.str, ".")) { return E_BAD_TYPE; } TimeSep = val->v.str[0]; return OK; } /***************************************************************/ /* */ /* HashVal */ /* Given a string, compute the hash value. */ /* */ /***************************************************************/ unsigned int HashVal(char const *str) { register unsigned int i=0; register unsigned int j=1; register unsigned int len=0; while(*str && len < VAR_NAME_LEN) { i += j * (unsigned int) UPPER(*str); str++; len++; j = 3-j; } return i; } /***************************************************************/ /* */ /* FindVar */ /* Given a string, find the variable whose name is that */ /* string. If create is 1, create the variable. */ /* */ /***************************************************************/ Var *FindVar(char const *str, int create) { register int h; register Var *v; register Var *prev; h = HashVal(str) % VAR_HASH_SIZE; v = VHashTbl[h]; prev = NULL; while(v) { if (! StrinCmp(str, v->name, VAR_NAME_LEN)) return v; prev = v; v = v-> next; } if (!create) return v; /* Create the variable */ v = NEW(Var); if (!v) return v; v->next = NULL; v->v.type = INT_TYPE; v->v.v.val = 0; v->preserve = 0; StrnCpy(v->name, str, VAR_NAME_LEN); if (prev) prev->next = v; else VHashTbl[h] = v; return v; } /***************************************************************/ /* */ /* DeleteVar */ /* Given a string, find the variable whose name is that */ /* string and delete it. */ /* */ /***************************************************************/ int DeleteVar(char const *str) { register int h; register Var *v; register Var *prev; h = HashVal(str) % VAR_HASH_SIZE; v = VHashTbl[h]; prev = NULL; while(v) { if (! StrinCmp(str, v->name, VAR_NAME_LEN)) break; prev = v; v = v-> next; } if (!v) return E_NOSUCH_VAR; DestroyValue(v->v); if (prev) prev->next = v->next; else VHashTbl[h] = v->next; free(v); return OK; } /***************************************************************/ /* */ /* SetVar */ /* */ /* Set the indicate variable to the specified value. */ /* */ /***************************************************************/ int SetVar(char const *str, Value *val) { Var *v = FindVar(str, 1); if (!v) return E_NO_MEM; /* Only way FindVar can fail */ DestroyValue(v->v); v->v = *val; return OK; } /***************************************************************/ /* */ /* GetVarValue */ /* */ /* Get a copy of the value of the variable. */ /* */ /***************************************************************/ int GetVarValue(char const *str, Value *val, Var *locals, ParsePtr p) { Var *v; /* Try searching local variables first */ v = locals; while (v) { if (! StrinCmp(str, v->name, VAR_NAME_LEN)) return CopyValue(val, &v->v); v = v->next; } /* Global variable... mark expression as non-constant */ if (p) p->nonconst_expr = 1; v=FindVar(str, 0); if (!v) { Eprint("%s: %s", ErrMsg[E_NOSUCH_VAR], str); return E_NOSUCH_VAR; } return CopyValue(val, &v->v); } /***************************************************************/ /* */ /* DoSet - set a variable. */ /* */ /***************************************************************/ int DoSet (Parser *p) { Value v; int r; DynamicBuffer buf; DBufInit(&buf); r = ParseIdentifier(p, &buf); if (r) return r; /* Allow optional equals-sign: SET var = value */ if (ParseNonSpaceChar(p, &r, 1) == '=') { ParseNonSpaceChar(p, &r, 0); } r = EvaluateExpr(p, &v); if (r) { DBufFree(&buf); return r; } if (*DBufValue(&buf) == '$') r = SetSysVar(DBufValue(&buf)+1, &v); else r = SetVar(DBufValue(&buf), &v); DBufFree(&buf); return r; } /***************************************************************/ /* */ /* DoUnset - delete a bunch of variables. */ /* */ /***************************************************************/ int DoUnset (Parser *p) { int r; DynamicBuffer buf; DBufInit(&buf); r = ParseToken(p, &buf); if (r) return r; if (!DBufLen(&buf)) { DBufFree(&buf); return E_EOLN; } (void) DeleteVar(DBufValue(&buf)); /* Ignore error - nosuchvar */ /* Keep going... */ while(1) { r = ParseToken(p, &buf); if (r) return r; if (!DBufLen(&buf)) { DBufFree(&buf); return OK; } (void) DeleteVar(DBufValue(&buf)); } } /***************************************************************/ /* */ /* DoDump */ /* */ /* Command file command to dump variable table. */ /* */ /***************************************************************/ int DoDump(ParsePtr p) { int r; Var *v; DynamicBuffer buf; if (PurgeMode) return OK; DBufInit(&buf); r = ParseToken(p, &buf); if (r) return r; if (!*DBufValue(&buf) || *DBufValue(&buf) == '#' || *DBufValue(&buf) == ';') { DBufFree(&buf); DumpVarTable(); return OK; } fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE); while(1) { if (*DBufValue(&buf) == '$') { DumpSysVarByName(DBufValue(&buf)+1); } else { v = FindVar(DBufValue(&buf), 0); DBufValue(&buf)[VAR_NAME_LEN] = 0; if (!v) fprintf(ErrFp, "%*s %s\n", VAR_NAME_LEN, DBufValue(&buf), UNDEF); else { fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name); PrintValue(&(v->v), ErrFp); fprintf(ErrFp, "\n"); } } r = ParseToken(p, &buf); if (r) return r; if (!*DBufValue(&buf) || *DBufValue(&buf) == '#' || *DBufValue(&buf) == ';') { DBufFree(&buf); return OK; } } } /***************************************************************/ /* */ /* DumpVarTable */ /* */ /* Dump the variable table to stderr. */ /* */ /***************************************************************/ void DumpVarTable(void) { register Var *v; register int i; fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE); for (i=0; iname); PrintValue(&(v->v), ErrFp); fprintf(ErrFp, "\n"); v = v->next; } } } /***************************************************************/ /* */ /* DestroyVars */ /* */ /* Free all the memory used by variables, but don't delete */ /* preserved variables unless ALL is non-zero. */ /* */ /***************************************************************/ void DestroyVars(int all) { int i; Var *v, *next, *prev; for (i=0; ipreserve) { DestroyValue(v->v); next = v->next; free(v); } else { if (prev) prev->next = v; else VHashTbl[i] = v; prev = v; next = v->next; v->next = NULL; } v = next; } } } /***************************************************************/ /* */ /* PreserveVar */ /* */ /* Given the name of a variable, "preserve" it. */ /* */ /***************************************************************/ int PreserveVar(char const *name) { Var *v; v = FindVar(name, 1); if (!v) return E_NO_MEM; v->preserve = 1; return OK; } /***************************************************************/ /* */ /* DoPreserve - preserve a bunch of variables. */ /* */ /***************************************************************/ int DoPreserve (Parser *p) { int r; DynamicBuffer buf; DBufInit(&buf); r = ParseToken(p, &buf); if (r) return r; if (!DBufLen(&buf)) { DBufFree(&buf); return E_EOLN; } r = PreserveVar(DBufValue(&buf)); DBufFree(&buf); if (r) return r; /* Keep going... */ while(1) { r = ParseToken(p, &buf); if (r) return r; if (!DBufLen(&buf)) { DBufFree(&buf); return OK; } r = PreserveVar(DBufValue(&buf)); DBufFree(&buf); if (r) return r; } } /***************************************************************/ /* */ /* SYSTEM VARIABLES */ /* */ /* Interface for modifying and reading system variables. */ /* */ /***************************************************************/ /* The structure of a system variable */ typedef struct { char const *name; char modifiable; int type; void *value; int min; int max; } SysVar; /* If the type of a sys variable is STR_TYPE, then min is redefined to be a flag indicating whether or not the value has been malloc'd. */ #define been_malloced min /* Flag for no min/max constraint */ #define ANY -31415926 /* All of the system variables sorted alphabetically */ static SysVar SysVarArr[] = { /* name mod type value min/mal max */ {"CalcUTC", 1, INT_TYPE, &CalculateUTC, 0, 1 }, {"CalMode", 0, INT_TYPE, &DoCalendar, 0, 0 }, {"Daemon", 0, INT_TYPE, &Daemon, 0, 0 }, {"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 }, {"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999}, {"DeltaOffset", 0, INT_TYPE, &DeltaOffset, 0, 0 }, {"DontFork", 0, INT_TYPE, &DontFork, 0, 0 }, {"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 }, {"DontTrigAts", 0, INT_TYPE, &DontIssueAts, 0, 0 }, {"EndSent", 1, STR_TYPE, &EndSent, 0, 0 }, {"EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0 }, {"FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132 }, {"FoldYear", 1, INT_TYPE, &FoldYear, 0, 1 }, {"FormWidth", 1, INT_TYPE, &FormWidth, 20, 132 }, {"HushMode", 0, INT_TYPE, &Hush, 0, 0 }, {"IgnoreOnce", 0, INT_TYPE, &IgnoreOnce, 0, 0 }, {"InfDelta", 0, INT_TYPE, &InfiniteDelta, 0, 0 }, {"LatDeg", 1, INT_TYPE, &LatDeg, -90, 90 }, {"LatMin", 1, INT_TYPE, &LatMin, -59, 59 }, {"LatSec", 1, INT_TYPE, &LatSec, -59, 59 }, {"Location", 1, STR_TYPE, &Location, 0, 0 }, {"LongDeg", 1, INT_TYPE, &LongDeg, -180, 180 }, {"LongMin", 1, INT_TYPE, &LongMin, -59, 59 }, {"LongSec", 1, INT_TYPE, &LongSec, -59, 59 }, {"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY }, {"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY }, {"MinsFromUTC", 1, INT_TYPE, &MinsFromUTC, -780, 780 }, {"NextMode", 0, INT_TYPE, &NextMode, 0, 0 }, {"NumQueued", 0, INT_TYPE, &NumQueued, 0, 0 }, {"NumTrig", 0, INT_TYPE, &NumTriggered, 0, 0 }, {"PrefixLineNo", 0, INT_TYPE, &DoPrefixLineNo, 0, 0 }, {"PSCal", 0, INT_TYPE, &PsCal, 0, 0 }, {"RunOff", 0, INT_TYPE, &RunDisabled, 0, 0 }, {"SimpleCal", 0, INT_TYPE, &DoSimpleCalendar, 0, 0 }, {"SortByDate", 0, INT_TYPE, &SortByDate, 0, 0 }, {"SortByPrio", 0, INT_TYPE, &SortByPrio, 0, 0 }, {"SortByTime", 0, INT_TYPE, &SortByTime, 0, 0 }, {"SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132 }, {"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0 }, {"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0 }, {"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 }, {"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 }, {"Tw", 0, SPECIAL_TYPE, trig_wday_func, 0, 0 }, {"Ty", 0, SPECIAL_TYPE, trig_year_func, 0, 0 }, {"U", 0, SPECIAL_TYPE, today_date_func, 0, 0 }, {"Ud", 0, SPECIAL_TYPE, today_day_func, 0, 0 }, {"Um", 0, SPECIAL_TYPE, today_mon_func, 0, 0 }, {"UntimedFirst", 0, INT_TYPE, &UntimedBeforeTimed, 0, 0 }, {"Uw", 0, SPECIAL_TYPE, today_wday_func, 0, 0 }, {"Uy", 0, SPECIAL_TYPE, today_year_func, 0, 0 } }; #define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) ) static SysVar *FindSysVar (char const *name); static void DumpSysVar (char const *name, const SysVar *v); /***************************************************************/ /* */ /* SetSysVar */ /* */ /* Set a system variable to the indicated value. */ /* */ /***************************************************************/ int SetSysVar(char const *name, Value *value) { SysVar *v = FindSysVar(name); if (!v) return E_NOSUCH_VAR; if (v->type != SPECIAL_TYPE && v->type != value->type) return E_BAD_TYPE; if (!v->modifiable) { Eprint("%s: `$%s'", ErrMsg[E_CANT_MODIFY], name); return E_CANT_MODIFY; } if (v->type == SPECIAL_TYPE) { SysVarFunc f = (SysVarFunc) v->value; return f(1, value); } else if (v->type == STR_TYPE) { /* If it's a string variable, special measures must be taken */ if (v->been_malloced) free(*((char **)(v->value))); v->been_malloced = 1; *((char **) v->value) = value->v.str; value->type = ERR_TYPE; /* So that it's not accidentally freed */ } else { if (v->max != ANY && value->v.val > v->max) return E_2HIGH; if (v->min != ANY && value->v.val < v->min) return E_2LOW; *((int *)v->value) = value->v.val; } return OK; } /***************************************************************/ /* */ /* GetSysVar */ /* */ /* Get the value of a system variable */ /* */ /***************************************************************/ int GetSysVar(char const *name, Value *val) { SysVar *v = FindSysVar(name); val->type = ERR_TYPE; if (!v) return E_NOSUCH_VAR; if (v->type == SPECIAL_TYPE) { SysVarFunc f = (SysVarFunc) v->value; return f(0, val); } else if (v->type == STR_TYPE) { val->v.str = StrDup(*((char **) v->value)); if (!val->v.str) return E_NO_MEM; } else { val->v.val = *((int *) v->value); } val->type = v->type; /* In "verbose" mode, print attempts to test $RunOff */ if (DebugFlag & DB_PRTLINE) { if (v->value == (void *) &RunDisabled) { Eprint("(Security note: $RunOff variable tested.)\n"); /* Allow further messages from this line */ FreshLine = 1; } } return OK; } /***************************************************************/ /* */ /* FindSysVar */ /* */ /* Find a system var with specified name. */ /* */ /***************************************************************/ static SysVar *FindSysVar(char const *name) { int top=NUMSYSVARS-1, bottom=0; int mid=(top + bottom) / 2; int r; while (top >= bottom) { r = StrCmpi(name, SysVarArr[mid].name); if (!r) return &SysVarArr[mid]; else if (r>0) bottom = mid+1; else top = mid-1; mid = (top+bottom) / 2; } return NULL; } /***************************************************************/ /* */ /* DumpSysVarByName */ /* */ /* Given the name of a system variable, display it. */ /* If name is "", dump all system variables. */ /* */ /***************************************************************/ void DumpSysVarByName(char const *name) { int i; SysVar *v; if (!name || !*name) { for (i=0; i VAR_NAME_LEN) { fprintf(ErrFp, "$%s: Name too long\n", name); return; } if (name) strcat(buffer, name); else strcat(buffer, v->name); fprintf(ErrFp, "%*s ", VAR_NAME_LEN+1, buffer); if (v) { if (v->type == SPECIAL_TYPE) { Value val; SysVarFunc f = (SysVarFunc) v->value; f(0, &val); PrintValue(&val, ErrFp); Putc('\n', ErrFp); DestroyValue(val); } else if (v->type == STR_TYPE) { char const *s = *((char **)v->value); int y; Putc('"', ErrFp); for (y=0; ytype == DATE_TYPE) { Value val; val.type = DATE_TYPE; val.v.val = * (int *) v->value; PrintValue(&val, ErrFp); Putc('\n', ErrFp); } else { if (!v->modifiable) fprintf(ErrFp, "%d\n", *((int *)v->value)); else { fprintf(ErrFp, "%-10d ", *((int *)v->value)); if (v->min == ANY) fprintf(ErrFp, "(-Inf, "); else fprintf(ErrFp, "[%d, ", v->min); if (v->max == ANY) fprintf(ErrFp, "Inf)\n"); else fprintf(ErrFp, "%d]\n", v->max); } } } else fprintf(ErrFp, "%s\n", UNDEF); return; } remind-03.01.15/src/version.h.in0000644000076400007640000000003411057403122014363 0ustar dfsdfs#define VERSION "@VERSION@" remind-03.01.15/tests/colors.rem0000644000076400007640000000114711672726753014534 0ustar dfsdfsREM 28 SPECIAL COLOR 0 0 0 Black REM 28 SPECIAL COLOR 65 0 0 Dim Red REM 28 SPECIAL COLOR 0 65 0 Dim Green REM 28 SPECIAL COLOR 0 0 65 Dim Blue REM 28 SPECIAL COLOR 0 65 65 Dim Cyan REM 28 SPECIAL COLOR 65 0 65 Dim Magenta REM 28 SPECIAL COLOR 65 65 0 Dim Yellow REM 28 SPECIAL COLOR 65 65 65 Dim White REM 28 SPECIAL COLOUR 129 0 0 Bright Red REM 28 SPECIAL COLOUR 0 129 0 Bright Green REM 28 SPECIAL COLOUR 0 0 129 Bright Blue REM 28 SPECIAL COLOUR 0 129 129 Bright Cyan REM 28 SPECIAL COLOUR 129 0 129 Bright Magenta REM 28 SPECIAL COLOUR 129 129 0 Bright Yellow REM 28 SPECIAL COLOUR 129 129 129 Bright White remind-03.01.15/tests/file.ps0000644000076400007640000000002311363110637013762 0ustar dfsdfs(Second-Bit-Of-PS) remind-03.01.15/tests/file2.ps0000644000076400007640000000002211363110637014043 0ustar dfsdfs(Fourth-Bit-Of-PS)remind-03.01.15/tests/include_dir/01.rem0000644000076400007640000000001611057403122015701 0ustar dfsdfsREM 15 MSG 01 remind-03.01.15/tests/include_dir/02.rem0000644000076400007640000000001611057403122015702 0ustar dfsdfsREM 15 MSG 02 remind-03.01.15/tests/include_dir/03.notrem0000644000076400007640000000001711057403122016425 0ustar dfsdfsREM MSG IGNORE remind-03.01.15/tests/include_dir/04cantread.rem0000644000076400007640000000004511057403122017410 0ustar dfsdfsREM 15 MSG You can't read this file. remind-03.01.15/tests/include_dir_no_rems/03.notrem0000644000076400007640000000001711057403122020147 0ustar dfsdfsREM MSG IGNORE remind-03.01.15/tests/include_test.rem0000644000076400007640000000014511057403122015665 0ustar dfsdfsINCLUDE include_dir INCLUDE include_dir_no_rems INCLUDE nonexistent_include_dir REM 15 MSG Whee!!!! remind-03.01.15/tests/purge_dir/f1.rem0000644000076400007640000000020711363377244015507 0ustar dfsdfs# This is f1.rem INCLUDE [filedir()]/f2.rem INCLUDE [filedir()]/f2.rem REM 1 Oct 1991 MSG old1. REM Monday UNTIL 1 Oct 1991 MSG old2.remind-03.01.15/tests/purge_dir/f2.rem0000644000076400007640000000013011363377244015503 0ustar dfsdfs# This is f2.rem REM 3 feb 2012 MSG new REM 3 1998 MSG old INCLUDE [filedir()]/f3.rem remind-03.01.15/tests/purge_dir/f3.rem0000644000076400007640000000257711363632267015524 0ustar dfsdfs# This is f3.rem REM Mon MSG repeat REM Mon SATISFY [1] MSG repeat IF 0 REM 1991 MSG wookie ENDIF IF 1 REM 1991 MSG wookie ENDIF IFTRIG 1991 REM MSG wookie ENDIF # More complex conditional statements IF 1 IF 0 REM 1991 MSG wookie ELSE REM 1991 MSG wookie ENDIF ELSE IF 1 REM 1991 MSG wookie ELSE REM 1991 MSG wookie ENDIF ENDIF REM [1990+1] MSG old-with-constant-expression REM [1990+1] \ MSG Continued line-old-with-constant-expression REM 1990 \ MSG expired-continued-line set y 1990 REM [y+1] MSG old-with-nonconstant-expression # A comment that should be preserved #!P A comment that should be nuked because it \ starts with #!P REM [y+1] \ MSG Continued-line-old-with-nonconstant-expression OMIT 25 Dec MSG woaaahh! OMIT 24 Dec OMIT 1 Jan 1992 MSG woaaahah... expired OMIT 2 Jan 1992 # Complicated expressions SET a 3 FSET const(x) x+3 FSET nonconst(x) x+a REM [const(5)] Jan 1992 MSG expired... should be commented out REM [const(a)] Jan 1992 MSG nonconstant expression REM [nonconst(5)] Jan 1992 MSG nonconstant expression REM [value("a")] Jan 1992 MSG nonconstant expression IF 0 # A comment in a false IF block #!P This should be nuked ENDIF # Busted line REM [0/0] Jan 1992 MSG ouch ERRMSG blorky FLUSH SET a 1 FSET a(x) x*x UNSET a CLEAR-OMIT-CONTEXT PUSH-OMIT-CONTEXT POP-OMIT-CONTEXT BANNER wow DEBUG +x DEBUG -x DUMP $ EXIT 0 PRESERVE i remind-03.01.15/tests/runinc.rem0000644000076400007640000000006311072203400014472 0ustar dfsdfsset s shell("echo 3") run on set s shell("echo 3") remind-03.01.15/tests/runtest.rem0000644000076400007640000000013711072203472014713 0ustar dfsdfsrun off set a shell("echo 2") run on set a shell("echo 2") run off include ../tests/runinc.rem remind-03.01.15/tests/shade.rem0000644000076400007640000000134611363110637014301 0ustar dfsdfsset $MinsFromUTC -240 set $CalcUTC 0 set $Location "Ottawa" set $LongDeg 75 set $LongMin 39 set $LongSec 0 set $LatDeg 45 set $LatMin 24 set $LatSec 0 IF $PSCAL [trigger(moondate(0))] SPECIAL MOON 0 -1 -1 [moontime(0)] [trigger(moondate(1))] SPECIAL MOON 1 -1 -1 [moontime(1)] [trigger(moondate(2))] SPECIAL MOON 2 -1 -1 [moontime(2)] [trigger(moondate(3))] SPECIAL MOON 3 -1 -1 [moontime(3)] ENDIF REM 4 PS (First-Bit-Of-PS) REM 4 PSFILE file.ps REM 4 PS (Third-Bit-Of-PS) REM 4 PSFILE file2.ps REM Mon SPECIAL SHADE 255 255 255 REM Tue SPECIAL SHADE 255 255 204 REM Wed SPECIAL SHADE 255 204 255 REM Thu SPECIAL SHADE 204 255 255 REM Fri SPECIAL SHADE 255 204 204 REM Sat SPECIAL SHADE 204 255 204 REM Sun SPECIAL SHADE 204 204 255 remind-03.01.15/tests/sun.rem0000644000076400007640000000032711676427605014035 0ustar dfsdfsSET $LatDeg 45 SET $LatMin 24 SET $LatSec 0 SET $LongDeg 75 SET $LongMin 39 SET $LongSec 0 SET $MinsFromUTC -300 SET $CalcUTC 0 MSG Dawn: [dawn()] MSG Sunrise: [sunrise()] MSG Sunset: [sunset()] MSG Dusk: [dusk()] remind-03.01.15/tests/test-rem0000644000076400007640000001042212514120342014157 0ustar dfsdfs#!/bin/sh # --------------------------------------------------------------------------- # TEST-REM # # This file runs an acceptance test for Remind. To use it, type: # sh test-rem OR make test # in the build directory. # # This file is part of REMIND. # Copyright (C) 1992-1997 Dianne Skoll # Copyright (C) 1999-2000 Roaring Penguin Software Inc. # --------------------------------------------------------------------------- DIR=`dirname $0` cd $DIR if test $? != 0 ; then echo "Unable to cd $DIR" >&2 exit 1 fi chmod 000 include_dir/04cantread.rem TEST_GETENV="foo bar baz" ; export TEST_GETENV echo "Test 1" > ../tests/test.out echo "" >> ../tests/test.out ../src/remind -e -dxte ../tests/test.rem 16 feb 1991 >> ../tests/test.out 2>&1 echo "" >> ../tests/test.out echo "Test 2" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -p -l ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1 echo "" >> ../tests/test.out echo "Test 3" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -s ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1 echo "" >> ../tests/test.out echo "Test 4" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -sa ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1 echo "Test 5" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -p -l -b0 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out 2>&1 echo "Test 6" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -p -l -b1 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out 2>&1 echo "Test 7" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -p -l -b2 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out 2>&1 echo "Test 8" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -df -p -l -b2 ../tests/include_dir 1 aug 2007 >> ../tests/test.out 2>&1 echo "Test 9" >> ../tests/test.out echo "" >> ../tests/test.out ../src/remind -df -p -l -b2 ../tests/nonexistent_include_dir 1 aug 2007 >> ../tests/test.out 2>&1 ../src/remind -df -p -l -b2 ../tests/include_dir_no_rems 1 aug 2007 >> ../tests/test.out 2>&1 ../src/remind -df -p -l -b2 ../tests/include_test.rem 1 aug 2007 >> ../tests/test.out 2>&1 chmod 644 include_dir/04cantread.rem echo "Color Test" >> ../tests/test.out ../src/remind -ccl ../tests/colors.rem 1 aug 2007 >> ../tests/test.out 2>&1 echo "MON WKDAY DAY across year test" >> ../tests/test.out echo 'REM Mon 29 Dec MSG x' | ../src/remind -dt - 1 Jan 2000 >> ../tests/test.out 2>&1 echo "Sort Test" >> ../tests/test.out (echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -q -gaaa - 1 Jan 2000 >> ../tests/test.out 2>&1 (echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -q -gaaad - 1 Jan 2000 >> ../tests/test.out 2>&1 echo "Purge Test" >> ../tests/test.out ../src/remind -j999 ../tests/purge_dir/f1.rem 3 Feb 2012 >> ../tests/test.out 2>&1 echo "F1" >> ../tests/test.out cat ../tests/purge_dir/f1.rem.purged >> ../tests/test.out echo "F2" >> ../tests/test.out cat ../tests/purge_dir/f2.rem.purged >> ../tests/test.out echo "F3" >> ../tests/test.out cat ../tests/purge_dir/f3.rem.purged >> ../tests/test.out rm -f ../tests/purge_dir/*.rem.purged >> ../tests/test.out 2>&1 ../src/remind ../tests/runtest.rem >> ../tests/test.out 2>&1 ../src/remind -p ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1 # The sun tests can fail due to math roundoff error changing the times # by a minute... # ../src/remind -p12 ../tests/sun.rem 1 Jan 2011 >> ../tests/test.out 2>&1 # Test -a vs -aa ../src/remind -q -a - 1 Jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1 REM 1 Jan 2012 AT 8:00 MSG 8am: Should not show up REM 1 Jan 2012 AT 9:00 MSG 9am: Should not show up REM 1 Jan 2012 AT 10:00 MSG 10am: Should not show up MSG [$DontTrigAts] EOF ../src/remind -q -a -a - 1 Jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1 REM 1 Jan 2012 AT 8:00 MSG 8am: Should not show up REM 1 Jan 2012 AT 9:00 MSG 9am: Should show up REM 1 Jan 2012 AT 10:00 MSG 10am: Should show up MSG [$DontTrigAts] EOF cmp -s ../tests/test.out ../tests/test.cmp if [ "$?" = "0" ]; then echo "Remind: Acceptance test PASSED" exit 0 else echo "Remind: Acceptance test FAILED" echo "" echo "Examine the file test.out to see where it differs from the" echo "reference file test.cmp." exit 1 fi remind-03.01.15/tests/test.cmp0000644000076400007640000037230112555504234014176 0ustar dfsdfsTest 1 # Test file for REMIND # # Use this file to test the date calculation routines # of the REMIND program by typing: # # ./test-rem # From WITHIN Remind source directory! # Don't evaluate SATISFY expressions if reminder has expired REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie ../tests/test.rem(10): Expired # bad AT REM AT 0:00 0:01 0:02 MSG foo ../tests/test.rem(13): Time specified twice REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())] ../tests/test.rem(15): Trig = Saturday, 16 February, 1991 Reminders for Saturday, 16th February, 1991: today() => 1991-02-16 hebday(1991-02-16) => 2 today() => 1991-02-16 hebmon(1991-02-16) => "Adar" today() => 1991-02-16 hebyear(1991-02-16) => 5751 Today is 2 Adar 5751 fset _h(x, y) trigger(hebdate(x,y)) [_h(1, "Tishrey")] MSG Rosh Hashana 1 Entering UserFN _h(1, "Tishrey") x => 1 y => "Tishrey" hebdate(1, "Tishrey") => 1991-09-09 trigger(1991-09-09) => "9 September 1991" Leaving UserFN _h() => "9 September 1991" ../tests/test.rem(18): Trig = Monday, 9 September, 1991 [_h(2, "Tishrey")] MSG Rosh Hashana 2 Entering UserFN _h(2, "Tishrey") x => 2 y => "Tishrey" hebdate(2, "Tishrey") => 1991-09-10 trigger(1991-09-10) => "10 September 1991" Leaving UserFN _h() => "10 September 1991" ../tests/test.rem(19): Trig = Tuesday, 10 September, 1991 [_h(3, "Tishrey")] MSG Tzom Gedalia Entering UserFN _h(3, "Tishrey") x => 3 y => "Tishrey" hebdate(3, "Tishrey") => 1991-09-11 trigger(1991-09-11) => "11 September 1991" Leaving UserFN _h() => "11 September 1991" ../tests/test.rem(20): Trig = Wednesday, 11 September, 1991 [_h(10, "Tishrey")] MSG Yom Kippur Entering UserFN _h(10, "Tishrey") x => 10 y => "Tishrey" hebdate(10, "Tishrey") => 1991-09-18 trigger(1991-09-18) => "18 September 1991" Leaving UserFN _h() => "18 September 1991" ../tests/test.rem(21): Trig = Wednesday, 18 September, 1991 [_h(15, "Tishrey")] MSG Sukkot 1 Entering UserFN _h(15, "Tishrey") x => 15 y => "Tishrey" hebdate(15, "Tishrey") => 1991-09-23 trigger(1991-09-23) => "23 September 1991" Leaving UserFN _h() => "23 September 1991" ../tests/test.rem(22): Trig = Monday, 23 September, 1991 [_h(25, "Kislev")] MSG Channuka Entering UserFN _h(25, "Kislev") x => 25 y => "Kislev" hebdate(25, "Kislev") => 1991-12-02 trigger(1991-12-02) => "2 December 1991" Leaving UserFN _h() => "2 December 1991" ../tests/test.rem(23): Trig = Monday, 2 December, 1991 [_h(10, "Tevet")] MSG Asara B'Tevet Entering UserFN _h(10, "Tevet") x => 10 y => "Tevet" hebdate(10, "Tevet") => 1991-12-17 trigger(1991-12-17) => "17 December 1991" Leaving UserFN _h() => "17 December 1991" ../tests/test.rem(24): Trig = Tuesday, 17 December, 1991 [_h(15, "Shvat")] MSG Tu B'Shvat Entering UserFN _h(15, "Shvat") x => 15 y => "Shvat" hebdate(15, "Shvat") => 1992-01-20 trigger(1992-01-20) => "20 January 1992" Leaving UserFN _h() => "20 January 1992" ../tests/test.rem(25): Trig = Monday, 20 January, 1992 [_h(15, "Adar A")] MSG Purim Katan Entering UserFN _h(15, "Adar A") x => 15 y => "Adar A" hebdate(15, "Adar A") => 1992-02-19 trigger(1992-02-19) => "19 February 1992" Leaving UserFN _h() => "19 February 1992" ../tests/test.rem(26): Trig = Wednesday, 19 February, 1992 [_h(14, "Adar")] MSG Purim Entering UserFN _h(14, "Adar") x => 14 y => "Adar" hebdate(14, "Adar") => 1991-02-28 trigger(1991-02-28) => "28 February 1991" Leaving UserFN _h() => "28 February 1991" ../tests/test.rem(27): Trig = Thursday, 28 February, 1991 [_h(15, "Nisan")] MSG Pesach Entering UserFN _h(15, "Nisan") x => 15 y => "Nisan" hebdate(15, "Nisan") => 1991-03-30 trigger(1991-03-30) => "30 March 1991" Leaving UserFN _h() => "30 March 1991" ../tests/test.rem(28): Trig = Saturday, 30 March, 1991 [_h(27, "Nisan")] MSG Yom HaShoah Entering UserFN _h(27, "Nisan") x => 27 y => "Nisan" hebdate(27, "Nisan") => 1991-04-11 trigger(1991-04-11) => "11 April 1991" Leaving UserFN _h() => "11 April 1991" ../tests/test.rem(29): Trig = Thursday, 11 April, 1991 [_h(4, "Iyar")] MSG Yom HaZikaron Entering UserFN _h(4, "Iyar") x => 4 y => "Iyar" hebdate(4, "Iyar") => 1991-04-18 trigger(1991-04-18) => "18 April 1991" Leaving UserFN _h() => "18 April 1991" ../tests/test.rem(30): Trig = Thursday, 18 April, 1991 [_h(5, "Iyar")] MSG Yom Ha'atzmaut Entering UserFN _h(5, "Iyar") x => 5 y => "Iyar" hebdate(5, "Iyar") => 1991-04-19 trigger(1991-04-19) => "19 April 1991" Leaving UserFN _h() => "19 April 1991" ../tests/test.rem(31): Trig = Friday, 19 April, 1991 [_h(28, "Iyar")] MSG Yom Yerushalayim Entering UserFN _h(28, "Iyar") x => 28 y => "Iyar" hebdate(28, "Iyar") => 1991-05-12 trigger(1991-05-12) => "12 May 1991" Leaving UserFN _h() => "12 May 1991" ../tests/test.rem(32): Trig = Sunday, 12 May, 1991 [_h(6, "Sivan")] MSG Shavuot Entering UserFN _h(6, "Sivan") x => 6 y => "Sivan" hebdate(6, "Sivan") => 1991-05-19 trigger(1991-05-19) => "19 May 1991" Leaving UserFN _h() => "19 May 1991" ../tests/test.rem(33): Trig = Sunday, 19 May, 1991 [_h(9, "Av")] MSG Tish'a B'Av Entering UserFN _h(9, "Av") x => 9 y => "Av" hebdate(9, "Av") => 1991-07-20 trigger(1991-07-20) => "20 July 1991" Leaving UserFN _h() => "20 July 1991" ../tests/test.rem(34): Trig = Saturday, 20 July, 1991 # Test some jahrzeit cases fset _i(x,y,z,a) trigger(hebdate(x,y,z,a)) [_i(30, "Heshvan", today(), 5759)] MSG Complete-Complete today() => 1991-02-16 Entering UserFN _i(30, "Heshvan", 1991-02-16, 5759) x => 30 y => "Heshvan" z => 1991-02-16 a => 5759 hebdate(30, "Heshvan", 1991-02-16, 5759) => 1991-11-07 trigger(1991-11-07) => "7 November 1991" Leaving UserFN _i() => "7 November 1991" ../tests/test.rem(38): Trig = Thursday, 7 November, 1991 [_i(30, "Heshvan", today(), 5760)] MSG Complete-Defective today() => 1991-02-16 Entering UserFN _i(30, "Heshvan", 1991-02-16, 5760) x => 30 y => "Heshvan" z => 1991-02-16 a => 5760 hebdate(30, "Heshvan", 1991-02-16, 5760) => 1991-11-07 trigger(1991-11-07) => "7 November 1991" Leaving UserFN _i() => "7 November 1991" ../tests/test.rem(39): Trig = Thursday, 7 November, 1991 [_i(30, "Heshvan", today(), 5761)] MSG Illegal today() => 1991-02-16 Entering UserFN _i(30, "Heshvan", 1991-02-16, 5761) x => 30 y => "Heshvan" z => 1991-02-16 a => 5761 hebdate(30, "Heshvan", 1991-02-16, 5761) => ../tests/test.rem(40): 30 Heshvan 5761: Invalid Hebrew date Invalid Hebrew date Leaving UserFN _i() => Invalid Hebrew date [_i(30, "Kislev", today(), 5759)] MSG Complete-Complete today() => 1991-02-16 Entering UserFN _i(30, "Kislev", 1991-02-16, 5759) x => 30 y => "Kislev" z => 1991-02-16 a => 5759 hebdate(30, "Kislev", 1991-02-16, 5759) => 1991-12-07 trigger(1991-12-07) => "7 December 1991" Leaving UserFN _i() => "7 December 1991" ../tests/test.rem(42): Trig = Saturday, 7 December, 1991 [_i(30, "Kislev", today(), 5760)] MSG Complete-Defective today() => 1991-02-16 Entering UserFN _i(30, "Kislev", 1991-02-16, 5760) x => 30 y => "Kislev" z => 1991-02-16 a => 5760 hebdate(30, "Kislev", 1991-02-16, 5760) => 1991-12-07 trigger(1991-12-07) => "7 December 1991" Leaving UserFN _i() => "7 December 1991" ../tests/test.rem(43): Trig = Saturday, 7 December, 1991 [_i(30, "Kislev", today(), 5761)] MSG Illegal today() => 1991-02-16 Entering UserFN _i(30, "Kislev", 1991-02-16, 5761) x => 30 y => "Kislev" z => 1991-02-16 a => 5761 hebdate(30, "Kislev", 1991-02-16, 5761) => ../tests/test.rem(44): 30 Kislev 5761: Invalid Hebrew date Invalid Hebrew date Leaving UserFN _i() => Invalid Hebrew date [_i(30, "Adar A", today(), 5755)] MSG Leap today() => 1991-02-16 Entering UserFN _i(30, "Adar A", 1991-02-16, 5755) x => 30 y => "Adar A" z => 1991-02-16 a => 5755 hebdate(30, "Adar A", 1991-02-16, 5755) => 1992-03-05 trigger(1992-03-05) => "5 March 1992" Leaving UserFN _i() => "5 March 1992" ../tests/test.rem(46): Trig = Thursday, 5 March, 1992 [_i(30, "Adar A", today(), 5756)] MSG Illegal today() => 1991-02-16 Entering UserFN _i(30, "Adar A", 1991-02-16, 5756) x => 30 y => "Adar A" z => 1991-02-16 a => 5756 hebdate(30, "Adar A", 1991-02-16, 5756) => ../tests/test.rem(47): No Adar A in 5756 Invalid Hebrew date Leaving UserFN _i() => Invalid Hebrew date [_i(29, "Adar A", today(), 5755)] MSG Leap today() => 1991-02-16 Entering UserFN _i(29, "Adar A", 1991-02-16, 5755) x => 29 y => "Adar A" z => 1991-02-16 a => 5755 hebdate(29, "Adar A", 1991-02-16, 5755) => 1991-03-15 trigger(1991-03-15) => "15 March 1991" Leaving UserFN _i() => "15 March 1991" ../tests/test.rem(48): Trig = Friday, 15 March, 1991 [_i(29, "Adar A", today(), 5756)] MSG Illegal today() => 1991-02-16 Entering UserFN _i(29, "Adar A", 1991-02-16, 5756) x => 29 y => "Adar A" z => 1991-02-16 a => 5756 hebdate(29, "Adar A", 1991-02-16, 5756) => ../tests/test.rem(49): No Adar A in 5756 Invalid Hebrew date Leaving UserFN _i() => Invalid Hebrew date # This causes a parse error on version 03.01.01 REM 1990-01-01 SATISFY 1 ../tests/test.rem(52): Expired # Test each possible case of the basic reminders. REM MSG Every Day ../tests/test.rem(56): Trig = Saturday, 16 February, 1991 Every Day REM 18 MSG Every 18th ../tests/test.rem(58): Trig = Monday, 18 February, 1991 REM 15 MSG Every 15th ../tests/test.rem(59): Trig = Friday, 15 March, 1991 REM Feb MSG February ../tests/test.rem(61): Trig = Saturday, 16 February, 1991 February REM Jan MSG January ../tests/test.rem(62): Trig = Wednesday, 1 January, 1992 REM March MSG March ../tests/test.rem(63): Trig = Friday, 1 March, 1991 REM 13 Jan MSG 13 Jan ../tests/test.rem(65): Trig = Monday, 13 January, 1992 REM 15 Feb MSG 15 Feb ../tests/test.rem(66): Trig = Saturday, 15 February, 1992 REM 28 Feb MSG 28 Feb ../tests/test.rem(67): Trig = Thursday, 28 February, 1991 REM 29 Feb MSG 29 Feb ../tests/test.rem(68): Trig = Saturday, 29 February, 1992 REM 5 Mar MSG 5 Mar ../tests/test.rem(69): Trig = Tuesday, 5 March, 1991 REM 1990 MSG 1990 ../tests/test.rem(71): Expired REM 1991 MSG 1991 ../tests/test.rem(72): Trig = Saturday, 16 February, 1991 1991 REM 1992 MSG 1991 ../tests/test.rem(73): Trig = Wednesday, 1 January, 1992 REM 1 1990 MSG 1 1990 ../tests/test.rem(75): Expired REM 29 1991 MSG 29 1991 ../tests/test.rem(76): Trig = Friday, 29 March, 1991 REM 29 1992 MSG 29 1992 ../tests/test.rem(77): Trig = Wednesday, 29 January, 1992 REM 16 1991 MSG 16 1991 ../tests/test.rem(78): Trig = Saturday, 16 February, 1991 16 1991 REM Jan 1990 MSG Jan 1990 ../tests/test.rem(80): Expired REM Feb 1991 MSG Feb 1991 ../tests/test.rem(81): Trig = Saturday, 16 February, 1991 Feb 1991 REM Dec 1991 MSG Dec 1991 ../tests/test.rem(82): Trig = Sunday, 1 December, 1991 REM May 1992 MSG May 1992 ../tests/test.rem(83): Trig = Friday, 1 May, 1992 REM 1 Jan 1991 MSG 1 Jan 1991 ../tests/test.rem(85): Expired REM 16 Feb 1991 MSG 16 Feb 1991 ../tests/test.rem(86): Trig = Saturday, 16 February, 1991 16 Feb 1991 REM 29 Dec 1992 MSG 29 Dec 1992 ../tests/test.rem(87): Trig = Tuesday, 29 December, 1992 REM Sun MSG Sun ../tests/test.rem(89): Trig = Sunday, 17 February, 1991 REM Fri Sat Tue MSG Fri Sat Tue ../tests/test.rem(90): Trig = Saturday, 16 February, 1991 Fri Sat Tue REM Sun 16 MSG Sun 16 ../tests/test.rem(92): Trig = Sunday, 17 February, 1991 REM Mon Tue Wed Thu Fri 1 MSG Mon Tue Wed Thu Fri 1 ../tests/test.rem(93): Trig = Friday, 1 March, 1991 REM Sun Feb MSG Sun Feb ../tests/test.rem(95): Trig = Sunday, 17 February, 1991 REM Mon Tue March MSG Mon Tue March ../tests/test.rem(96): Trig = Monday, 4 March, 1991 REM Sun 16 Feb MSG Sun 16 Feb ../tests/test.rem(98): Trig = Sunday, 17 February, 1991 REM Mon Tue 10 March MSG Mon Tue 10 March ../tests/test.rem(99): Trig = Monday, 11 March, 1991 REM Sat Sun 1991 MSG Sat Sun 1991 ../tests/test.rem(101): Trig = Saturday, 16 February, 1991 Sat Sun 1991 REM Mon Tue 1992 MSG Mon Tue 1992 ../tests/test.rem(102): Trig = Monday, 6 January, 1992 REM Sun 16 1991 MSG Sun 16 1991 ../tests/test.rem(104): Trig = Sunday, 17 February, 1991 REM Mon Tue Wed Thu Fri 1 1992 MSG Mon Tue Wed Thu Fri 1 1992 ../tests/test.rem(105): Trig = Wednesday, 1 January, 1992 REM Mon Feb 1991 MSG Mon Feb 1991 ../tests/test.rem(107): Trig = Monday, 18 February, 1991 REM Tue Jan 1992 MSG Tue Jan 1992 ../tests/test.rem(108): Trig = Tuesday, 7 January, 1992 REM Sun Mon 16 Feb 1991 MSG Sun Mon 16 Feb 1991 ../tests/test.rem(110): Trig = Sunday, 17 February, 1991 REM Tue 28 Jan 1992 MSG Tue 28 Jan 1992 ../tests/test.rem(111): Trig = Tuesday, 28 January, 1992 # Try some Backs CLEAR-OMIT-CONTEXT REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun ../tests/test.rem(115): Trig = Thursday, 28 February, 1991 REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun ../tests/test.rem(116): Trig = Thursday, 28 February, 1991 OMIT 28 Feb REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun (28 Feb omitted) ../tests/test.rem(119): Trig = Wednesday, 27 February, 1991 REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun (28 Feb omitted) ../tests/test.rem(120): Trig = Thursday, 28 February, 1991 CLEAR-OMIT-CONTEXT # Try out UNTIL REM Wed UNTIL 21 Feb 1991 MSG Wed UNTIL 21 Feb 1991 ../tests/test.rem(125): Trig = Wednesday, 20 February, 1991 # Try playing with the OMIT context OMIT 28 Feb 1991 REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted) ../tests/test.rem(130): Trig = Wednesday, 27 February, 1991 REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted) ../tests/test.rem(131): Trig = Thursday, 28 February, 1991 REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted) ../tests/test.rem(132): Trig = Wednesday, 27 February, 1991 REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted) ../tests/test.rem(133): Trig = Friday, 28 February, 1992 REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted) ../tests/test.rem(134): Trig = Friday, 1 March, 1991 PUSH-OMIT-CONTEXT CLEAR-OMIT-CONTEXT REM 1 Mar -1 MSG 1 mar -1 ../tests/test.rem(138): Trig = Thursday, 28 February, 1991 REM 1 Mar --1 MSG 1 mar --1 ../tests/test.rem(139): Trig = Thursday, 28 February, 1991 REM 28 Feb BEFORE MSG 28 Feb BEFORE ../tests/test.rem(140): Trig = Thursday, 28 February, 1991 REM 28 Feb SKIP MSG 28 Feb SKIP ../tests/test.rem(141): Trig = Thursday, 28 February, 1991 REM 28 Feb AFTER MSG 28 Feb AFTER ../tests/test.rem(142): Trig = Thursday, 28 February, 1991 POP-OMIT-CONTEXT REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted) ../tests/test.rem(145): Trig = Wednesday, 27 February, 1991 REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted) ../tests/test.rem(146): Trig = Thursday, 28 February, 1991 REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted) ../tests/test.rem(147): Trig = Wednesday, 27 February, 1991 REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted) ../tests/test.rem(148): Trig = Friday, 28 February, 1992 REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted) ../tests/test.rem(149): Trig = Friday, 1 March, 1991 REM 13 March 1991 *1 UNTIL 19 March 1991 MSG 13-19 Mar 91 ../tests/test.rem(152): Trig = Wednesday, 13 March, 1991 # Test BACK CLEAR-OMIT-CONTEXT REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 ../tests/test.rem(156): Trig = Monday, 18 February, 1991 OMIT 17 Feb 1991 REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 (17Feb91 omitted) ../tests/test.rem(159): Trig = Monday, 18 February, 1991 18 Feb 1991 +1 (17Feb91 omitted) REM 18 Feb 1991 ++1 MSG 18 Feb 1991 ++1 (17Feb91 omitted) ../tests/test.rem(160): Trig = Monday, 18 February, 1991 CLEAR-OMIT-CONTEXT # Test the scanfrom clause REM Fri SATISFY 1 ../tests/test.rem(164): Trig = Friday, 22 February, 1991 OMIT [trigger(trigdate())] trigdate() => 1991-02-22 trigger(1991-02-22) => "22 February 1991" REM Fri after MSG 23 Feb 1991 ../tests/test.rem(166): Trig = Saturday, 23 February, 1991 CLEAR-OMIT-CONTEXT REM Fri SCANFROM [trigger(today()-7)] SATISFY 1 today() => 1991-02-16 1991-02-16 - 7 => 1991-02-09 trigger(1991-02-09) => "9 February 1991" ../tests/test.rem(168): Trig = Friday, 15 February, 1991 OMIT [trigger(trigdate())] trigdate() => 1991-02-15 trigger(1991-02-15) => "15 February 1991" REM Fri after MSG 16 Feb 1991 ../tests/test.rem(170): Trig = Saturday, 16 February, 1991 16 Feb 1991 CLEAR-OMIT-CONTEXT # Test omitfunc fset _ofunc(x) (day(x) < 7 || day(x) % 2) REM 1 March OMITFUNC _ofunc AFTER MSG OmitFunc Test Entering UserFN _ofunc(1991-02-15) x => 1991-02-15 day(1991-02-15) => 15 15 < 7 => 0 x => 1991-02-15 day(1991-02-15) => 15 15 % 2 => 1 0 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-02-14) x => 1991-02-14 day(1991-02-14) => 14 14 < 7 => 0 x => 1991-02-14 day(1991-02-14) => 14 14 % 2 => 0 0 || 0 => 0 Leaving UserFN _ofunc() => 0 Entering UserFN _ofunc(1991-03-01) x => 1991-03-01 day(1991-03-01) => 1 1 < 7 => 1 x => 1991-03-01 day(1991-03-01) => 1 1 % 2 => 1 1 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-02) x => 1991-03-02 day(1991-03-02) => 2 2 < 7 => 1 x => 1991-03-02 day(1991-03-02) => 2 2 % 2 => 0 1 || 0 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-03) x => 1991-03-03 day(1991-03-03) => 3 3 < 7 => 1 x => 1991-03-03 day(1991-03-03) => 3 3 % 2 => 1 1 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-04) x => 1991-03-04 day(1991-03-04) => 4 4 < 7 => 1 x => 1991-03-04 day(1991-03-04) => 4 4 % 2 => 0 1 || 0 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-05) x => 1991-03-05 day(1991-03-05) => 5 5 < 7 => 1 x => 1991-03-05 day(1991-03-05) => 5 5 % 2 => 1 1 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-06) x => 1991-03-06 day(1991-03-06) => 6 6 < 7 => 1 x => 1991-03-06 day(1991-03-06) => 6 6 % 2 => 0 1 || 0 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-07) x => 1991-03-07 day(1991-03-07) => 7 7 < 7 => 0 x => 1991-03-07 day(1991-03-07) => 7 7 % 2 => 1 0 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-08) x => 1991-03-08 day(1991-03-08) => 8 8 < 7 => 0 x => 1991-03-08 day(1991-03-08) => 8 8 % 2 => 0 0 || 0 => 0 Leaving UserFN _ofunc() => 0 ../tests/test.rem(175): Trig = Friday, 8 March, 1991 REM 8 March OMITFUNC _ofunc -1 MSG OmitFunc Test 2 Entering UserFN _ofunc(1991-03-07) x => 1991-03-07 day(1991-03-07) => 7 7 < 7 => 0 x => 1991-03-07 day(1991-03-07) => 7 7 % 2 => 1 0 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-06) x => 1991-03-06 day(1991-03-06) => 6 6 < 7 => 1 x => 1991-03-06 day(1991-03-06) => 6 6 % 2 => 0 1 || 0 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-05) x => 1991-03-05 day(1991-03-05) => 5 5 < 7 => 1 x => 1991-03-05 day(1991-03-05) => 5 5 % 2 => 1 1 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-04) x => 1991-03-04 day(1991-03-04) => 4 4 < 7 => 1 x => 1991-03-04 day(1991-03-04) => 4 4 % 2 => 0 1 || 0 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-03) x => 1991-03-03 day(1991-03-03) => 3 3 < 7 => 1 x => 1991-03-03 day(1991-03-03) => 3 3 % 2 => 1 1 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-02) x => 1991-03-02 day(1991-03-02) => 2 2 < 7 => 1 x => 1991-03-02 day(1991-03-02) => 2 2 % 2 => 0 1 || 0 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-03-01) x => 1991-03-01 day(1991-03-01) => 1 1 < 7 => 1 x => 1991-03-01 day(1991-03-01) => 1 1 % 2 => 1 1 || 1 => 1 Leaving UserFN _ofunc() => 1 Entering UserFN _ofunc(1991-02-28) x => 1991-02-28 day(1991-02-28) => 28 28 < 7 => 0 x => 1991-02-28 day(1991-02-28) => 28 28 % 2 => 0 0 || 0 => 0 Leaving UserFN _ofunc() => 0 ../tests/test.rem(176): Trig = Thursday, 28 February, 1991 # omitfunc ignores local/global omits fset _ofunc(x) 0 OMIT 1 March OMIT 2 March 1991 REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March ../tests/test.rem(182): Warning: OMIT is ignored if you use OMITFUNC Entering UserFN _ofunc(1991-02-15) Leaving UserFN _ofunc() => 0 Entering UserFN _ofunc(1991-03-01) Leaving UserFN _ofunc() => 0 ../tests/test.rem(182): Trig = Friday, 1 March, 1991 REM 1 March OMIT Sun AFTER MSG Should trigger 4 March ../tests/test.rem(183): Trig = Monday, 4 March, 1991 # Test shorthand reminders REM 1991-02-28 MSG Feb 28 ../tests/test.rem(186): Trig = Thursday, 28 February, 1991 REM 1991/02/28@14:45 MSG Feb 28 ../tests/test.rem(187): Trig = Thursday, 28 February, 1991 REM Wed UNTIL 1991-01-01 MSG Expired ../tests/test.rem(188): Expired REM Wed SCANFROM 1991-02-26 MSG SCANFROM ../tests/test.rem(189): Trig = Wednesday, 27 February, 1991 set a000 abs(1) abs(1) => 1 set a001 abs(-1) - 1 => -1 abs(-1) => 1 set a002 asc("foo") asc("foo") => 102 set a003 baseyr() baseyr() => 1990 set a004 char(66,55,66,77,66) char(66, 55, 66, 77, 66) => "B7BMB" set a005 choose(3, "foo", "bar", "baz", "blech") choose(3, "foo", "bar", "baz", "blech") => "baz" set a006 coerce("string", 1) coerce("string", 1) => "1" set a007 coerce("string", today()) today() => 1991-02-16 coerce("string", 1991-02-16) => "1991-02-16" set a008 coerce("string", 11:44) coerce("string", 11:44) => "11:44" set a009 coerce("int", "badnews") coerce("int", "badnews") => Can't coerce ../tests/test.rem(200): Can't coerce set a010 coerce("int", "12") coerce("int", "12") => 12 set a011 coerce("int", 11:44) coerce("int", 11:44) => 704 set a012 coerce("int", today()) today() => 1991-02-16 coerce("int", 1991-02-16) => 411 set a013 date(1992, 2, 2) date(1992, 2, 2) => 1992-02-02 set a014 date(1993, 2, 29) date(1993, 2, 29) => Bad date specification ../tests/test.rem(205): Bad date specification set a015 day(today()) today() => 1991-02-16 day(1991-02-16) => 16 set a016 daysinmon(2, 1991) daysinmon(2, 1991) => 28 set a017 daysinmon(2, 1992) daysinmon(2, 1992) => 29 set a018 defined("a017") defined("a017") => 1 set a019 defined("a019") defined("a019") => 0 set a020 filename() filename() => "../tests/test.rem" set a021 getenv("TEST_GETENV") getenv("TEST_GETENV") => "foo bar baz" set a022 hour(11:22) hour(11:22) => 11 set a023 iif(1, 1, 0) iif(1, 1, 0) => 1 set a024 iif(0, 1, 0) iif(0, 1, 0) => 0 set a025 index("barfoobar", "foo") index("barfoobar", "foo") => 4 set a026 index("barfoobar", "bar", 2) index("barfoobar", "bar", 2) => 7 set a027 isleap(today()) today() => 1991-02-16 isleap(1991-02-16) => 0 set a028 isleap(1992) isleap(1992) => 1 omit [trigger(today())] today() => 1991-02-16 trigger(1991-02-16) => "16 February 1991" set a030 isomitted(today()) today() => 1991-02-16 isomitted(1991-02-16) => 1 clear set a029 isomitted(today()) today() => 1991-02-16 isomitted(1991-02-16) => 0 set a031 lower("FOOBARBAZ") lower("FOOBARBAZ") => "foobarbaz" set a032 max(1, 2, 34, 1, 3) max(1, 2, 34, 1, 3) => 34 set a033 max("foo", "bar", "baz") max("foo", "bar", "baz") => "foo" set a034 max(today(), today()+1, today()-1) today() => 1991-02-16 today() => 1991-02-16 1991-02-16 + 1 => 1991-02-17 today() => 1991-02-16 1991-02-16 - 1 => 1991-02-15 max(1991-02-16, 1991-02-17, 1991-02-15) => 1991-02-17 set a035 min(1, 2, 34, 1, 3) min(1, 2, 34, 1, 3) => 1 set a036 min("foo", "bar", "baz") min("foo", "bar", "baz") => "bar" set a037 min(today(), today()+1, today()-1) today() => 1991-02-16 today() => 1991-02-16 1991-02-16 + 1 => 1991-02-17 today() => 1991-02-16 1991-02-16 - 1 => 1991-02-15 min(1991-02-16, 1991-02-17, 1991-02-15) => 1991-02-15 set a038 minute(11:33) minute(11:33) => 33 set a039 mon(today()) today() => 1991-02-16 mon(1991-02-16) => "February" set a040 monnum(today()) today() => 1991-02-16 monnum(1991-02-16) => 2 set a041 ord(3) ord(3) => "3rd" set a042 ord(4) ord(4) => "4th" set a043 ostype() ostype() => "UNIX" set a044 plural(2) plural(2) => "s" set a045 plural(2, "ies") plural(2, "ies") => "iess" set a046 plural(2, "y", "ies") plural(2, "y", "ies") => "ies" set a047 sgn(-2) - 2 => -2 sgn(-2) => -1 set a048 shell("echo foo") shell("echo foo") => "foo" set a049 strlen("sadjflkhsldkfhsdlfjhk") strlen("sadjflkhsldkfhsdlfjhk") => 21 set a050 substr(a049, 2) a049 => 21 substr(21, 2) => Type mismatch ../tests/test.rem(243): Type mismatch set a051 substr(a050, 2, 6) a050 => ../tests/test.rem(244): Undefined variable: a050 set a052 time(1+2, 3+4) 1 + 2 => 3 3 + 4 => 7 time(3, 7) => 03:07 rem 10 jan 1992 AT 11:22 CAL ../tests/test.rem(246): Trig = Friday, 10 January, 1992 set a053 trigdate() trigdate() => 1992-01-10 set a054 trigtime() trigtime() => 11:22 set a055 trigvalid() trigvalid() => 1 set a056 upper("sdfjhsdf ksjdfh kjsdfh ksjdfh") upper("sdfjhsdf ksjdfh kjsdfh ksjdfh") => "SDFJHSDF KSJDFH KJSDFH KSJDFH" set a057 value("a05"+"6") "a05" + "6" => "a056" value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH" set a058 version() version() => "03.01.15" set a059 wkday(today()) today() => 1991-02-16 wkday(1991-02-16) => "Saturday" set a060 wkdaynum(today()) today() => 1991-02-16 wkdaynum(1991-02-16) => 6 set a061 year(today()) today() => 1991-02-16 year(1991-02-16) => 1991 set a062 1+2*(3+4-(5*7/2)) 3 + 4 => 7 5 * 7 => 35 35 / 2 => 17 7 - 17 => -10 2 * -10 => -20 1 + -20 => -19 set a063 1>=2 1 >= 2 => 0 set a064 1<2 || 3 > 4 1 < 2 => 1 3 > 4 => 0 1 || 0 => 1 set a065 1 && 1 1 && 1 => 1 set a066 !a065 a065 => 1 ! 1 => 0 set a067 typeof(2) typeof(2) => "INT" set a068 typeof("foo") typeof("foo") => "STRING" set a069 typeof(11:33) typeof(11:33) => "TIME" set a070 typeof(today()) today() => 1991-02-16 typeof(1991-02-16) => "DATE" fset g(x,y) max(x,y) fset h(x,y) min(g(x+y, x*y), g(x-y, x/y)) set a071 g(1, 2) Entering UserFN g(1, 2) x => 1 y => 2 max(1, 2) => 2 Leaving UserFN g() => 2 set a072 h(2, 3) Entering UserFN h(2, 3) x => 2 y => 3 2 + 3 => 5 x => 2 y => 3 2 * 3 => 6 Entering UserFN g(5, 6) x => 5 y => 6 max(5, 6) => 6 Leaving UserFN g() => 6 x => 2 y => 3 2 - 3 => -1 x => 2 y => 3 2 / 3 => 0 Entering UserFN g(-1, 0) x => -1 y => 0 max(-1, 0) => 0 Leaving UserFN g() => 0 min(6, 0) => 0 Leaving UserFN h() => 0 set a073 h("foo", 11:33) Entering UserFN h("foo", 11:33) x => "foo" y => 11:33 "foo" + 11:33 => "foo11:33" x => "foo" y => 11:33 "foo" * 11:33 => Type mismatch ../tests/test.rem(269): `*': Type mismatch Leaving UserFN h() => Type mismatch set a074 dosubst("%a %b %c %d %e %f %g %h", '1992/5/5') dosubst("%a %b %c %d %e %f %g %h", 1992-05-05) => "on Tuesday, 5 May, 1992 in 444 days' tim"... msg [a074]% ../tests/test.rem(271): Trig = Saturday, 16 February, 1991 a074 => "on Tuesday, 5 May, 1992 in 444 days' tim"... on Tuesday, 5 May, 1992 in 444 days' time on Tuesday 5 on 05-05-1992 on 05-05-1992 on Tuesday, 5 May on 05-05 set a075 dosubst("%i %j %k %l %m %n %o %p", '1992/5/5') dosubst("%i %j %k %l %m %n %o %p", 1992-05-05) => "on 05-05 on Tuesday, May 5th, 1992 on Tu"... msg [a075]% ../tests/test.rem(273): Trig = Saturday, 16 February, 1991 a075 => "on 05-05 on Tuesday, May 5th, 1992 on Tu"... on 05-05 on Tuesday, May 5th, 1992 on Tuesday, May 5th on 1992-05-05 May 5 s set a076 dosubst("%q %r %s %t %u %v %w %x", '1992/5/5') dosubst("%q %r %s %t %u %v %w %x", 1992-05-05) => "s' 05 th 05 on Tuesday, 5th May, 1992 on"... msg [a076]% ../tests/test.rem(275): Trig = Saturday, 16 February, 1991 a076 => "s' 05 th 05 on Tuesday, 5th May, 1992 on"... s' 05 th 05 on Tuesday, 5th May, 1992 on Tuesday, 5th May Tuesday 444 set a074 dosubst("%*a %*b %*c %*d %*e %*f %*g %*h", '1992/5/5') dosubst("%*a %*b %*c %*d %*e %*f %*g %*h", 1992-05-05) => "Tuesday, 5 May, 1992 in 444 days' time T"... msg [a074]% ../tests/test.rem(277): Trig = Saturday, 16 February, 1991 a074 => "Tuesday, 5 May, 1992 in 444 days' time T"... Tuesday, 5 May, 1992 in 444 days' time Tuesday 5 05-05-1992 05-05-1992 Tuesday, 5 May 05-05 set a075 dosubst("%*i %*j %*k %*l %*m %*n %*o %*p", '1992/5/5') dosubst("%*i %*j %*k %*l %*m %*n %*o %*p", 1992-05-05) => "05-05 Tuesday, May 5th, 1992 Tuesday, Ma"... msg [a075]% ../tests/test.rem(279): Trig = Saturday, 16 February, 1991 a075 => "05-05 Tuesday, May 5th, 1992 Tuesday, Ma"... 05-05 Tuesday, May 5th, 1992 Tuesday, May 5th 1992-05-05 May 5 s set a076 dosubst("%*q %*r %*s %*t %*u %*v %*w %*x", '1992/5/5') dosubst("%*q %*r %*s %*t %*u %*v %*w %*x", 1992-05-05) => "s' 05 th 05 Tuesday, 5th May, 1992 Tuesd"... msg [a076]% ../tests/test.rem(281): Trig = Saturday, 16 February, 1991 a076 => "s' 05 th 05 Tuesday, 5th May, 1992 Tuesd"... s' 05 th 05 Tuesday, 5th May, 1992 Tuesday, 5th May Tuesday 444 set a077 dosubst("%*y %*z", '1992/5/5') dosubst("%*y %*z", 1992-05-05) => "1992 92 " msg [a077]% ../tests/test.rem(283): Trig = Saturday, 16 February, 1991 a077 => "1992 92 " 1992 92 set a074 dosubst("%A %B %C %D %E %F %G %H", '1992/5/5') dosubst("%A %B %C %D %E %F %G %H", 1992-05-05) => "On Tuesday, 5 May, 1992 In 444 days' tim"... msg [a074]% ../tests/test.rem(285): Trig = Saturday, 16 February, 1991 a074 => "On Tuesday, 5 May, 1992 In 444 days' tim"... On Tuesday, 5 May, 1992 In 444 days' time On Tuesday 5 On 05-05-1992 On 05-05-1992 On Tuesday, 5 May On 05-05 set a075 dosubst("%I %J %K %L %M %N %O %P", '1992/5/5') dosubst("%I %J %K %L %M %N %O %P", 1992-05-05) => "On 05-05 On Tuesday, May 5th, 1992 On Tu"... msg [a075]% ../tests/test.rem(287): Trig = Saturday, 16 February, 1991 a075 => "On 05-05 On Tuesday, May 5th, 1992 On Tu"... On 05-05 On Tuesday, May 5th, 1992 On Tuesday, May 5th On 1992-05-05 May 5 S set a076 dosubst("%Q %R %S %T %U %V %W %X", '1992/5/5') dosubst("%Q %R %S %T %U %V %W %X", 1992-05-05) => "S' 05 Th 05 On Tuesday, 5th May, 1992 On"... msg [a076]% ../tests/test.rem(289): Trig = Saturday, 16 February, 1991 a076 => "S' 05 Th 05 On Tuesday, 5th May, 1992 On"... S' 05 Th 05 On Tuesday, 5th May, 1992 On Tuesday, 5th May Tuesday 444 set a077 dosubst("%Y %Z", '1992/5/5') dosubst("%Y %Z", 1992-05-05) => "1992 92 " msg [a077]% ../tests/test.rem(291): Trig = Saturday, 16 February, 1991 a077 => "1992 92 " 1992 92 set a074 dosubst("%*A %*B %*C %*D %*E %*F %*G %*H", '1992/5/5') dosubst("%*A %*B %*C %*D %*E %*F %*G %*H", 1992-05-05) => "Tuesday, 5 May, 1992 In 444 days' time T"... msg [a074]% ../tests/test.rem(293): Trig = Saturday, 16 February, 1991 a074 => "Tuesday, 5 May, 1992 In 444 days' time T"... Tuesday, 5 May, 1992 In 444 days' time Tuesday 5 05-05-1992 05-05-1992 Tuesday, 5 May 05-05 set a075 dosubst("%*I %*J %*K %*L %*M %*N %*O %*P", '1992/5/5') dosubst("%*I %*J %*K %*L %*M %*N %*O %*P", 1992-05-05) => "05-05 Tuesday, May 5th, 1992 Tuesday, Ma"... msg [a075]% ../tests/test.rem(295): Trig = Saturday, 16 February, 1991 a075 => "05-05 Tuesday, May 5th, 1992 Tuesday, Ma"... 05-05 Tuesday, May 5th, 1992 Tuesday, May 5th 1992-05-05 May 5 S set a076 dosubst("%*Q %*R %*S %*T %*U %*V %*W %*X", '1992/5/5') dosubst("%*Q %*R %*S %*T %*U %*V %*W %*X", 1992-05-05) => "S' 05 Th 05 Tuesday, 5th May, 1992 Tuesd"... msg [a076]% ../tests/test.rem(297): Trig = Saturday, 16 February, 1991 a076 => "S' 05 Th 05 Tuesday, 5th May, 1992 Tuesd"... S' 05 Th 05 Tuesday, 5th May, 1992 Tuesday, 5th May Tuesday 444 set a077 dosubst("%*Y %*Z", '1992/5/5') dosubst("%*Y %*Z", 1992-05-05) => "1992 92 " msg [a077]% ../tests/test.rem(299): Trig = Saturday, 16 February, 1991 a077 => "1992 92 " 1992 92 set a078 easterdate(today()) today() => 1991-02-16 easterdate(1991-02-16) => 1991-03-31 set a079 easterdate(1992) easterdate(1992) => 1992-04-19 set a080 easterdate(1995) easterdate(1995) => 1995-04-16 set a081 "" OMIT 1991-03-11 set a082 slide('1991-03-01', 7, "Sat", "Sun") slide(1991-03-01, 7, "Sat", "Sun") => 1991-03-13 set a083 slide('1991-04-01', -7, "Sat") - 7 => -7 slide(1991-04-01, -7, "Sat") => 1991-03-24 set a084 nonomitted('1991-03-01', '1991-03-13', "Sat", "Sun") nonomitted(1991-03-01, 1991-03-13, "Sat", "Sun") => 7 set a085 nonomitted('1991-03-24', '1991-04-01', "Sat") nonomitted(1991-03-24, 1991-04-01, "Sat") => 7 dump Variable Value a017 29 a036 "bar" a055 1 a074 "Tuesday, 5 May, 1992 In 444 days' time T"... a008 "11:44" a027 0 a046 "ies" a065 1 a084 7 a018 1 a037 1991-02-15 a056 "SDFJHSDF KSJDFH KJSDFH KSJDFH" a075 "05-05 Tuesday, May 5th, 1992 Tuesday, Ma"... a028 1 a047 -1 a066 0 a085 7 a019 0 a038 33 a057 "SDFJHSDF KSJDFH KJSDFH KSJDFH" a076 "S' 05 Th 05 Tuesday, 5th May, 1992 Tuesd"... a029 0 a048 "foo" a067 "INT" a039 "February" a058 "03.01.15" a077 "1992 92 " a049 21 a068 "STRING" a059 "Saturday" a078 1991-03-31 a069 "TIME" a079 1992-04-19 a000 1 a010 12 a001 1 a020 "../tests/test.rem" a011 704 a030 1 a002 102 a021 "foo bar baz" a040 2 a012 411 a031 "foobarbaz" a003 1990 a022 11 a041 "3rd" a060 6 a013 1992-02-02 a032 34 a070 "DATE" a004 "B7BMB" a023 1 a042 "4th" a061 1991 a080 1995-04-16 a033 "foo" a052 03:07 a071 2 a005 "baz" a024 0 a043 "UNIX" a062 -19 a081 "" a015 16 a034 1991-02-17 a053 1992-01-10 a072 0 a006 "1" a025 4 a044 "s" a063 0 a082 1991-03-13 a016 28 a035 1 a054 11:22 a007 "1991-02-16" a026 7 a045 "iess" a064 1 a083 1991-03-24 dump $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Variable Value $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: Name too long OMIT 2010-09-03 THROUGH 2010-09-15 OMIT December 25 MSG X ../tests/test.rem(312): Trig = Wednesday, 25 December, 1991 # Next should give a parse error OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal ../tests/test.rem(314): Trig = Sunday, 26 December, 2010 OMIT DUMP Global Full OMITs (16 of maximum allowed 500): 1991-03-11 2010-09-03 2010-09-04 2010-09-05 2010-09-06 2010-09-07 2010-09-08 2010-09-09 2010-09-10 2010-09-11 2010-09-12 2010-09-13 2010-09-14 2010-09-15 2010-12-26 2010-12-27 Global Partial OMITs (1 of maximum allowed 366): 12-25 Test 2 # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 # fileinfo 17 ../tests/test2.rem 2007/08/01 COLOR * * * 0 0 255 Blue Wednesday # fileinfo 27 ../tests/test2.rem 2007/08/01 * * * * 0 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/01 * * * * 0 NonOmit-2 # fileinfo 18 ../tests/test2.rem 2007/08/02 COLOR * * * 255 0 0 Red Thursday # fileinfo 27 ../tests/test2.rem 2007/08/02 * * * * 1 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/02 * * * * 1 NonOmit-2 # fileinfo 21 ../tests/test2.rem 2007/08/03 SHADE * * * 0 255 0 # fileinfo 27 ../tests/test2.rem 2007/08/03 * * * * 2 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/03 * * * * 2 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/04 * * * * 3 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/04 * * * * 3 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/05 * * * * 4 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/05 * * * * 3 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/06 * * * * 5 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/06 * * * * 3 NonOmit-2 # fileinfo 43 ../tests/test2.rem 2007/08/06 * * * * Blort # fileinfo 27 ../tests/test2.rem 2007/08/07 * * * * 6 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/07 * * * * 4 NonOmit-2 # fileinfo 17 ../tests/test2.rem 2007/08/08 COLOR * * * 0 0 255 Blue Wednesday # fileinfo 27 ../tests/test2.rem 2007/08/08 * * * * 7 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/08 * * * * 5 NonOmit-2 # fileinfo 18 ../tests/test2.rem 2007/08/09 COLOR * * * 255 0 0 Red Thursday # fileinfo 27 ../tests/test2.rem 2007/08/09 * * * * 8 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/09 * * * * 6 NonOmit-2 # fileinfo 21 ../tests/test2.rem 2007/08/10 SHADE * * * 0 255 0 # fileinfo 27 ../tests/test2.rem 2007/08/10 * * * * 9 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/10 * * * * 7 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/11 * * * * 10 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/11 * * * * 8 NonOmit-2 # fileinfo 24 ../tests/test2.rem 2007/08/12 MOON * * * 0 # fileinfo 27 ../tests/test2.rem 2007/08/12 * * * * 11 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/12 * * * * 8 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/13 * * * * 12 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/13 * * * * 8 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/14 * * * * 13 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/14 * * * * 9 NonOmit-2 # fileinfo 17 ../tests/test2.rem 2007/08/15 COLOR * * * 0 0 255 Blue Wednesday # fileinfo 27 ../tests/test2.rem 2007/08/15 * * * * 13 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/15 * * * * 9 NonOmit-2 # fileinfo 18 ../tests/test2.rem 2007/08/16 COLOR * * * 255 0 0 Red Thursday # fileinfo 27 ../tests/test2.rem 2007/08/16 * * * * 14 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/16 * * * * 10 NonOmit-2 # fileinfo 21 ../tests/test2.rem 2007/08/17 SHADE * * * 0 255 0 # fileinfo 27 ../tests/test2.rem 2007/08/17 * * * * 15 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/17 * * * * 11 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/18 * * * * 16 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/18 * * * * 12 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/19 * * * * 17 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/19 * * * * 12 NonOmit-2 # fileinfo 31 ../tests/test2.rem 2007/08/20 COLOR * * 825 6 7 8 1:45pm Mooo! # fileinfo 27 ../tests/test2.rem 2007/08/20 * * * * 18 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/20 * * * * 12 NonOmit-2 # fileinfo 43 ../tests/test2.rem 2007/08/20 * * * * Blort # fileinfo 34 ../tests/test2.rem 2007/08/21 PostScript * * 115 (wookie) show # fileinfo 27 ../tests/test2.rem 2007/08/21 * * * * 19 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/21 * * * * 13 NonOmit-2 # fileinfo 17 ../tests/test2.rem 2007/08/22 COLOR * * * 0 0 255 Blue Wednesday # fileinfo 27 ../tests/test2.rem 2007/08/22 * * * * 20 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/22 * * * * 14 NonOmit-2 # fileinfo 35 ../tests/test2.rem 2007/08/22 PostScript * * * (cabbage) show # fileinfo 38 ../tests/test2.rem 2007/08/23 blort * * 1004 snoo glup # fileinfo 18 ../tests/test2.rem 2007/08/23 COLOR * * * 255 0 0 Red Thursday # fileinfo 27 ../tests/test2.rem 2007/08/23 * * * * 21 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/23 * * * * 15 NonOmit-2 # fileinfo 21 ../tests/test2.rem 2007/08/24 SHADE * * * 0 255 0 # fileinfo 27 ../tests/test2.rem 2007/08/24 * * * * 22 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/24 * * * * 16 NonOmit-2 # fileinfo 39 ../tests/test2.rem 2007/08/24 blort * * * gulp wookie # fileinfo 27 ../tests/test2.rem 2007/08/25 * * * * 23 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/25 * * * * 17 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/26 * * * * 24 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/26 * * * * 17 NonOmit-2 # fileinfo 27 ../tests/test2.rem 2007/08/27 * * * * 25 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/27 * * * * 17 NonOmit-2 # fileinfo 43 ../tests/test2.rem 2007/08/27 * * * * Blort # fileinfo 27 ../tests/test2.rem 2007/08/28 * * * * 26 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/28 * * * * 18 NonOmit-2 # fileinfo 17 ../tests/test2.rem 2007/08/29 COLOR * * * 0 0 255 Blue Wednesday # fileinfo 27 ../tests/test2.rem 2007/08/29 * * * * 27 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/29 * * * * 19 NonOmit-2 # fileinfo 18 ../tests/test2.rem 2007/08/30 COLOR * * * 255 0 0 Red Thursday # fileinfo 27 ../tests/test2.rem 2007/08/30 * * * * 28 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/30 * * * * 20 NonOmit-2 # fileinfo 21 ../tests/test2.rem 2007/08/31 SHADE * * * 0 255 0 # fileinfo 27 ../tests/test2.rem 2007/08/31 * * * * 29 NonOmit-1 # fileinfo 28 ../tests/test2.rem 2007/08/31 * * * * 21 NonOmit-2 # rem2ps end Test 3 2007/08/01 COLOR * * * 0 0 255 Blue Wednesday 2007/08/01 * * * * 0 NonOmit-1 2007/08/01 * * * * 0 NonOmit-2 2007/08/02 COLOR * * * 255 0 0 Red Thursday 2007/08/02 * * * * 1 NonOmit-1 2007/08/02 * * * * 1 NonOmit-2 2007/08/03 * * * * 2 NonOmit-1 2007/08/03 * * * * 2 NonOmit-2 2007/08/04 * * * * 3 NonOmit-1 2007/08/04 * * * * 3 NonOmit-2 2007/08/05 * * * * 4 NonOmit-1 2007/08/05 * * * * 3 NonOmit-2 2007/08/06 * * * * 5 NonOmit-1 2007/08/06 * * * * 3 NonOmit-2 2007/08/06 * * * * Blort 2007/08/07 * * * * 6 NonOmit-1 2007/08/07 * * * * 4 NonOmit-2 2007/08/08 COLOR * * * 0 0 255 Blue Wednesday 2007/08/08 * * * * 7 NonOmit-1 2007/08/08 * * * * 5 NonOmit-2 2007/08/09 COLOR * * * 255 0 0 Red Thursday 2007/08/09 * * * * 8 NonOmit-1 2007/08/09 * * * * 6 NonOmit-2 2007/08/10 * * * * 9 NonOmit-1 2007/08/10 * * * * 7 NonOmit-2 2007/08/11 * * * * 10 NonOmit-1 2007/08/11 * * * * 8 NonOmit-2 2007/08/12 * * * * 11 NonOmit-1 2007/08/12 * * * * 8 NonOmit-2 2007/08/13 * * * * 12 NonOmit-1 2007/08/13 * * * * 8 NonOmit-2 2007/08/14 * * * * 13 NonOmit-1 2007/08/14 * * * * 9 NonOmit-2 2007/08/15 COLOR * * * 0 0 255 Blue Wednesday 2007/08/15 * * * * 13 NonOmit-1 2007/08/15 * * * * 9 NonOmit-2 2007/08/16 COLOR * * * 255 0 0 Red Thursday 2007/08/16 * * * * 14 NonOmit-1 2007/08/16 * * * * 10 NonOmit-2 2007/08/17 * * * * 15 NonOmit-1 2007/08/17 * * * * 11 NonOmit-2 2007/08/18 * * * * 16 NonOmit-1 2007/08/18 * * * * 12 NonOmit-2 2007/08/19 * * * * 17 NonOmit-1 2007/08/19 * * * * 12 NonOmit-2 2007/08/20 COLOR * * 825 6 7 8 1:45pm Mooo! 2007/08/20 * * * * 18 NonOmit-1 2007/08/20 * * * * 12 NonOmit-2 2007/08/20 * * * * Blort 2007/08/21 * * * * 19 NonOmit-1 2007/08/21 * * * * 13 NonOmit-2 2007/08/22 COLOR * * * 0 0 255 Blue Wednesday 2007/08/22 * * * * 20 NonOmit-1 2007/08/22 * * * * 14 NonOmit-2 2007/08/23 COLOR * * * 255 0 0 Red Thursday 2007/08/23 * * * * 21 NonOmit-1 2007/08/23 * * * * 15 NonOmit-2 2007/08/24 * * * * 22 NonOmit-1 2007/08/24 * * * * 16 NonOmit-2 2007/08/25 * * * * 23 NonOmit-1 2007/08/25 * * * * 17 NonOmit-2 2007/08/26 * * * * 24 NonOmit-1 2007/08/26 * * * * 17 NonOmit-2 2007/08/27 * * * * 25 NonOmit-1 2007/08/27 * * * * 17 NonOmit-2 2007/08/27 * * * * Blort 2007/08/28 * * * * 26 NonOmit-1 2007/08/28 * * * * 18 NonOmit-2 2007/08/29 COLOR * * * 0 0 255 Blue Wednesday 2007/08/29 * * * * 27 NonOmit-1 2007/08/29 * * * * 19 NonOmit-2 2007/08/30 COLOR * * * 255 0 0 Red Thursday 2007/08/30 * * * * 28 NonOmit-1 2007/08/30 * * * * 20 NonOmit-2 2007/08/31 * * * * 29 NonOmit-1 2007/08/31 * * * * 21 NonOmit-2 Test 4 2007/08/01 COLOR * * * 0 0 255 Blue Wednesday 2007/08/01 * * * * 0 NonOmit-1 2007/08/01 * * * * 0 NonOmit-2 2007/08/02 COLOR * * * 255 0 0 Red Thursday 2007/08/02 * * * * 1 NonOmit-1 2007/08/02 * * * * 1 NonOmit-2 2007/08/03 * * * * 2 NonOmit-1 2007/08/03 * * * * 2 NonOmit-2 2007/08/04 * * * * 3 NonOmit-1 2007/08/04 * * * * 3 NonOmit-2 2007/08/05 * * * * 4 NonOmit-1 2007/08/05 * * * * 3 NonOmit-2 2007/08/06 COLOR * * * 0 0 255 Blue Wednesday is in 2 days' time 2007/08/06 * * * * 5 NonOmit-1 2007/08/06 * * * * 3 NonOmit-2 2007/08/06 * * * * Blort 2007/08/07 COLOR * * * 0 0 255 Blue Wednesday is tomorrow 2007/08/07 * * * * 6 NonOmit-1 2007/08/07 * * * * 4 NonOmit-2 2007/08/08 COLOR * * * 0 0 255 Blue Wednesday 2007/08/08 * * * * 7 NonOmit-1 2007/08/08 * * * * 5 NonOmit-2 2007/08/09 COLOR * * * 255 0 0 Red Thursday 2007/08/09 * * * * 8 NonOmit-1 2007/08/09 * * * * 6 NonOmit-2 2007/08/10 * * * * 9 NonOmit-1 2007/08/10 * * * * 7 NonOmit-2 2007/08/11 * * * * 10 NonOmit-1 2007/08/11 * * * * 8 NonOmit-2 2007/08/12 COLOR * * * 0 0 255 Blue Wednesday is in 3 days' time 2007/08/12 * * * * 11 NonOmit-1 2007/08/12 * * * * 8 NonOmit-2 2007/08/13 COLOR * * * 0 0 255 Blue Wednesday is in 2 days' time 2007/08/13 * * * * 12 NonOmit-1 2007/08/13 * * * * 8 NonOmit-2 2007/08/14 COLOR * * * 0 0 255 Blue Wednesday is tomorrow 2007/08/14 * * * * 13 NonOmit-1 2007/08/14 * * * * 9 NonOmit-2 2007/08/15 COLOR * * * 0 0 255 Blue Wednesday 2007/08/15 * * * * 13 NonOmit-1 2007/08/15 * * * * 9 NonOmit-2 2007/08/16 COLOR * * * 255 0 0 Red Thursday 2007/08/16 * * * * 14 NonOmit-1 2007/08/16 * * * * 10 NonOmit-2 2007/08/17 * * * * 15 NonOmit-1 2007/08/17 * * * * 11 NonOmit-2 2007/08/18 * * * * 16 NonOmit-1 2007/08/18 * * * * 12 NonOmit-2 2007/08/19 * * * * 17 NonOmit-1 2007/08/19 * * * * 12 NonOmit-2 2007/08/20 COLOR * * 825 6 7 8 1:45pm Mooo! 2007/08/20 COLOR * * * 0 0 255 Blue Wednesday is in 2 days' time 2007/08/20 * * * * 18 NonOmit-1 2007/08/20 * * * * 12 NonOmit-2 2007/08/20 * * * * Blort 2007/08/21 COLOR * * * 0 0 255 Blue Wednesday is tomorrow 2007/08/21 * * * * 19 NonOmit-1 2007/08/21 * * * * 13 NonOmit-2 2007/08/22 COLOR * * * 0 0 255 Blue Wednesday 2007/08/22 * * * * 20 NonOmit-1 2007/08/22 * * * * 14 NonOmit-2 2007/08/23 COLOR * * * 255 0 0 Red Thursday 2007/08/23 * * * * 21 NonOmit-1 2007/08/23 * * * * 15 NonOmit-2 2007/08/24 * * * * 22 NonOmit-1 2007/08/24 * * * * 16 NonOmit-2 2007/08/25 * * * * 23 NonOmit-1 2007/08/25 * * * * 17 NonOmit-2 2007/08/26 * * * * 24 NonOmit-1 2007/08/26 * * * * 17 NonOmit-2 2007/08/27 COLOR * * * 0 0 255 Blue Wednesday is in 2 days' time 2007/08/27 * * * * 25 NonOmit-1 2007/08/27 * * * * 17 NonOmit-2 2007/08/27 * * * * Blort 2007/08/28 COLOR * * * 0 0 255 Blue Wednesday is tomorrow 2007/08/28 * * * * 26 NonOmit-1 2007/08/28 * * * * 18 NonOmit-2 2007/08/29 COLOR * * * 0 0 255 Blue Wednesday 2007/08/29 * * * * 27 NonOmit-1 2007/08/29 * * * * 19 NonOmit-2 2007/08/30 COLOR * * * 255 0 0 Red Thursday 2007/08/30 * * * * 28 NonOmit-1 2007/08/30 * * * * 20 NonOmit-2 2007/08/31 * * * * 29 NonOmit-1 2007/08/31 * * * * 21 NonOmit-2 Test 5 # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 # fileinfo 1 ../tests/test3.rem 2007/08/01 * * * 660 11:00am Wookie # fileinfo 5 ../tests/test3.rem 2007/08/01 * * 45 660 11:00-11:45am Lettuce # fileinfo 9 ../tests/test3.rem 2007/08/01 * * 105 660 11:00am-12:45pm Apple # fileinfo 13 ../tests/test3.rem 2007/08/01 * * 885 660 11:00am-1:45am+1 Green # fileinfo 17 ../tests/test3.rem 2007/08/01 * * 1485 660 11:00am-11:45am+1 Yellow # fileinfo 21 ../tests/test3.rem 2007/08/01 * * 2205 660 11:00am-11:45pm+1 Purple # fileinfo 25 ../tests/test3.rem 2007/08/01 * * 2925 660 11:00am-11:45am+2 Sad # fileinfo 2 ../tests/test3.rem 2007/08/01 * * * 720 12:00pm Cookie # fileinfo 6 ../tests/test3.rem 2007/08/01 * * 45 720 12:00-12:45pm Cabbage # fileinfo 10 ../tests/test3.rem 2007/08/01 * * 165 720 12:00-2:45pm Pear # fileinfo 14 ../tests/test3.rem 2007/08/01 * * 885 720 12:00pm-2:45am+1 Blue # fileinfo 18 ../tests/test3.rem 2007/08/01 * * 1485 720 12:00pm-12:45pm+1 Orange # fileinfo 22 ../tests/test3.rem 2007/08/01 * * 2205 720 12:00pm-12:45am+2 Black # fileinfo 26 ../tests/test3.rem 2007/08/01 * * 2925 720 12:00pm-12:45pm+2 Happy # fileinfo 3 ../tests/test3.rem 2007/08/01 * * * 780 1:00pm Snookie # fileinfo 7 ../tests/test3.rem 2007/08/01 * * 45 780 1:00-1:45pm Tomato # fileinfo 11 ../tests/test3.rem 2007/08/01 * * 225 780 1:00-4:45pm Grape # fileinfo 15 ../tests/test3.rem 2007/08/01 * * 885 780 1:00pm-3:45am+1 Red # fileinfo 19 ../tests/test3.rem 2007/08/01 * * 1485 780 1:00pm-1:45pm+1 Magenta # fileinfo 23 ../tests/test3.rem 2007/08/01 * * 2205 780 1:00pm-1:45am+2 Brown # fileinfo 27 ../tests/test3.rem 2007/08/01 * * 2925 780 1:00pm-1:45pm+2 Strange # rem2ps end Test 6 # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 # fileinfo 1 ../tests/test3.rem 2007/08/01 * * * 660 11:00 Wookie # fileinfo 5 ../tests/test3.rem 2007/08/01 * * 45 660 11:00-11:45 Lettuce # fileinfo 9 ../tests/test3.rem 2007/08/01 * * 105 660 11:00-12:45 Apple # fileinfo 13 ../tests/test3.rem 2007/08/01 * * 885 660 11:00-01:45+1 Green # fileinfo 17 ../tests/test3.rem 2007/08/01 * * 1485 660 11:00-11:45+1 Yellow # fileinfo 21 ../tests/test3.rem 2007/08/01 * * 2205 660 11:00-23:45+1 Purple # fileinfo 25 ../tests/test3.rem 2007/08/01 * * 2925 660 11:00-11:45+2 Sad # fileinfo 2 ../tests/test3.rem 2007/08/01 * * * 720 12:00 Cookie # fileinfo 6 ../tests/test3.rem 2007/08/01 * * 45 720 12:00-12:45 Cabbage # fileinfo 10 ../tests/test3.rem 2007/08/01 * * 165 720 12:00-14:45 Pear # fileinfo 14 ../tests/test3.rem 2007/08/01 * * 885 720 12:00-02:45+1 Blue # fileinfo 18 ../tests/test3.rem 2007/08/01 * * 1485 720 12:00-12:45+1 Orange # fileinfo 22 ../tests/test3.rem 2007/08/01 * * 2205 720 12:00-00:45+2 Black # fileinfo 26 ../tests/test3.rem 2007/08/01 * * 2925 720 12:00-12:45+2 Happy # fileinfo 3 ../tests/test3.rem 2007/08/01 * * * 780 13:00 Snookie # fileinfo 7 ../tests/test3.rem 2007/08/01 * * 45 780 13:00-13:45 Tomato # fileinfo 11 ../tests/test3.rem 2007/08/01 * * 225 780 13:00-16:45 Grape # fileinfo 15 ../tests/test3.rem 2007/08/01 * * 885 780 13:00-03:45+1 Red # fileinfo 19 ../tests/test3.rem 2007/08/01 * * 1485 780 13:00-13:45+1 Magenta # fileinfo 23 ../tests/test3.rem 2007/08/01 * * 2205 780 13:00-01:45+2 Brown # fileinfo 27 ../tests/test3.rem 2007/08/01 * * 2925 780 13:00-13:45+2 Strange # rem2ps end Test 7 # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 # fileinfo 1 ../tests/test3.rem 2007/08/01 * * * 660 Wookie # fileinfo 5 ../tests/test3.rem 2007/08/01 * * 45 660 Lettuce # fileinfo 9 ../tests/test3.rem 2007/08/01 * * 105 660 Apple # fileinfo 13 ../tests/test3.rem 2007/08/01 * * 885 660 Green # fileinfo 17 ../tests/test3.rem 2007/08/01 * * 1485 660 Yellow # fileinfo 21 ../tests/test3.rem 2007/08/01 * * 2205 660 Purple # fileinfo 25 ../tests/test3.rem 2007/08/01 * * 2925 660 Sad # fileinfo 2 ../tests/test3.rem 2007/08/01 * * * 720 Cookie # fileinfo 6 ../tests/test3.rem 2007/08/01 * * 45 720 Cabbage # fileinfo 10 ../tests/test3.rem 2007/08/01 * * 165 720 Pear # fileinfo 14 ../tests/test3.rem 2007/08/01 * * 885 720 Blue # fileinfo 18 ../tests/test3.rem 2007/08/01 * * 1485 720 Orange # fileinfo 22 ../tests/test3.rem 2007/08/01 * * 2205 720 Black # fileinfo 26 ../tests/test3.rem 2007/08/01 * * 2925 720 Happy # fileinfo 3 ../tests/test3.rem 2007/08/01 * * * 780 Snookie # fileinfo 7 ../tests/test3.rem 2007/08/01 * * 45 780 Tomato # fileinfo 11 ../tests/test3.rem 2007/08/01 * * 225 780 Grape # fileinfo 15 ../tests/test3.rem 2007/08/01 * * 885 780 Red # fileinfo 19 ../tests/test3.rem 2007/08/01 * * 1485 780 Magenta # fileinfo 23 ../tests/test3.rem 2007/08/01 * * 2205 780 Brown # fileinfo 27 ../tests/test3.rem 2007/08/01 * * 2925 780 Strange # rem2ps end Test 8 Scanning directory `../tests/include_dir' for *.rem files Caching directory `../tests/include_dir' listing Reading `../tests/include_dir/01.rem': Opening file on disk Caching file `../tests/include_dir/01.rem' in memory Reading `../tests/include_dir/02.rem': Opening file on disk Caching file `../tests/include_dir/02.rem' in memory Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem Found cached directory listing for `../tests/include_dir' Reading `../tests/include_dir/01.rem': Found in cache Reading `../tests/include_dir/02.rem': Found in cache Reading `../tests/include_dir/04cantread.rem': Opening file on disk ../tests/include_dir/02.rem(1): Can't open file: ../tests/include_dir/04cantread.rem # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 # fileinfo 1 ../tests/include_dir/01.rem 2007/08/15 * * * * 01 # fileinfo 1 ../tests/include_dir/02.rem 2007/08/15 * * * * 02 # rem2ps end Test 9 Reading `../tests/nonexistent_include_dir': Opening file on disk Can't open file: ../tests/nonexistent_include_dir Error reading ../tests/nonexistent_include_dir: Can't open file # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 Scanning directory `../tests/include_dir_no_rems' for *.rem files Caching directory `../tests/include_dir_no_rems' listing ../tests/include_dir_no_rems: No files matching *.rem Error reading ../tests/include_dir_no_rems: No files matching *.rem # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 Reading `../tests/include_test.rem': Opening file on disk Caching file `../tests/include_test.rem' in memory Scanning directory `include_dir' for *.rem files Caching directory `include_dir' listing Reading `include_dir/01.rem': Opening file on disk Caching file `include_dir/01.rem' in memory Reading `include_dir/02.rem': Opening file on disk Caching file `include_dir/02.rem' in memory Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Scanning directory `include_dir_no_rems' for *.rem files Caching directory `include_dir_no_rems' listing ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir Reading `../tests/include_test.rem': Found in cache Found cached directory listing for `include_dir' Reading `include_dir/01.rem': Found in cache Reading `include_dir/02.rem': Found in cache Reading `include_dir/04cantread.rem': Opening file on disk include_dir/02.rem(1): Can't open file: include_dir/04cantread.rem Found cached directory listing for `include_dir_no_rems' ../tests/include_test.rem(2): include_dir_no_rems: No files matching *.rem Reading `nonexistent_include_dir': Opening file on disk ../tests/include_test.rem(3): Can't open file: nonexistent_include_dir # rem2ps begin August 2007 31 3 0 Sunday Monday Tuesday Wednesday Thursday Friday Saturday July 31 September 30 # fileinfo 1 include_dir/01.rem 2007/08/15 * * * * 01 # fileinfo 1 include_dir/02.rem 2007/08/15 * * * * 02 # fileinfo 5 ../tests/include_test.rem 2007/08/15 * * * * Whee!!!! # rem2ps end Color Test (0lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk(B (0x(B August 2007 (0x(B (0tqqqqqqqqqqwqqqqqqqqqqwqqqqqqqqqqwqqqqqqqqqqwqqqqqqqqqqwqqqqqqqqqqwqqqqqqqqqqu(B (0x(B Sunday (0x(B Monday (0x(B Tuesday (0x(BWednesday (0x(B Thursday (0x(B Friday (0x(B Saturday (0x(B (0tqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqu(B (0x(B (0x(B (0x(B (0x(B1 (0x(B2 (0x(B3 (0x(B4 (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0tqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqu(B (0x(B5 (0x(B6 (0x(B7 (0x(B8 (0x(B9 (0x(B10 (0x(B11 (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0tqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqu(B (0x(B12 (0x(B13 (0x(B14 (0x(B15 (0x(B16 (0x(B17 (0x(B18 (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0tqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqu(B (0x(B19 (0x(B20 (0x(B21 (0x(B22 (0x(B23 (0x(B24 (0x(B25 (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0tqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqu(B (0x(B26 (0x(B27 (0x(B28 (0x(B29 (0x(B30 (0x(B31 (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBlack (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BDim Red (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BDim Green (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BDim Blue (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BDim Cyan (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BDim (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BMagenta (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BDim Yellow(0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BDim White (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBright Red(0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBright (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BGreen (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBright (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBlue (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBright (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BCyan (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBright (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BMagenta (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBright (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BYellow (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BBright (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(B (0x(BWhite (0x(B (0x(B (0x(B (0x(B (0x(B (0mqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqj(B MON WKDAY DAY across year test -(1): Trig = Monday, 3 January, 2000 No reminders. Sort Test Reminders for Saturday, 1st January, 2000: Untimed Timed Reminders for Saturday, 1st January, 2000: Timed Untimed Purge Test ../tests/purge_dir/f3.rem(76): `/': Division by zero ../tests/purge_dir/f3.rem(76): `/': Division by zero F1 # This is f1.rem INCLUDE [filedir()]/f2.rem INCLUDE [filedir()]/f2.rem #!P: Expired: REM 1 Oct 1991 MSG old1. #!P: Expired: REM Monday UNTIL 1 Oct 1991 MSG old2. F2 # This is f2.rem REM 3 feb 2012 MSG new #!P: Expired: REM 3 1998 MSG old INCLUDE [filedir()]/f3.rem F3 # This is f3.rem REM Mon MSG repeat #!P: Cannot purge SATISFY-type reminders REM Mon SATISFY [1] MSG repeat #!P: The next IF evaluated false... #!P: REM statements in IF block not checked for purging. IF 0 REM 1991 MSG wookie ENDIF IF 1 #!P: Expired: REM 1991 MSG wookie ENDIF #!P: The next IFTRIG did not trigger. #!P: REM statements in IFTRIG block not checked for purging. IFTRIG 1991 REM MSG wookie ENDIF # More complex conditional statements IF 1 #!P: The next IF evaluated false... #!P: REM statements in IF block not checked for purging. IF 0 REM 1991 MSG wookie ELSE #!P: Expired: REM 1991 MSG wookie ENDIF #!P: The previous IF evaluated true. #!P: REM statements in ELSE block not checked for purging ELSE IF 1 REM 1991 MSG wookie ELSE REM 1991 MSG wookie ENDIF ENDIF #!P: Next line has expired, but contains expression... please verify #!P: Expired: REM [1990+1] MSG old-with-constant-expression #!P: Next line has expired, but contains expression... please verify #!P: Expired: REM [1990+1] \ MSG Continued line-old-with-constant-expression #!P: Expired: REM 1990 \ MSG expired-continued-line set y 1990 #!P: Next line may have expired, but contains non-constant expression REM [y+1] MSG old-with-nonconstant-expression # A comment that should be preserved #!P: Next line may have expired, but contains non-constant expression REM [y+1] \ MSG Continued-line-old-with-nonconstant-expression OMIT 25 Dec MSG woaaahh! OMIT 24 Dec #!P: Expired: OMIT 1 Jan 1992 MSG woaaahah... expired OMIT 2 Jan 1992 # Complicated expressions SET a 3 FSET const(x) x+3 FSET nonconst(x) x+a #!P: Next line has expired, but contains expression... please verify #!P: Expired: REM [const(5)] Jan 1992 MSG expired... should be commented out #!P: Next line may have expired, but contains non-constant expression REM [const(a)] Jan 1992 MSG nonconstant expression #!P: Next line may have expired, but contains non-constant expression REM [nonconst(5)] Jan 1992 MSG nonconstant expression #!P: Next line may have expired, but contains non-constant expression REM [value("a")] Jan 1992 MSG nonconstant expression #!P: The next IF evaluated false... #!P: REM statements in IF block not checked for purging. IF 0 # A comment in a false IF block ENDIF # Busted line #!P! Could not parse next line: Division by zero REM [0/0] Jan 1992 MSG ouch ERRMSG blorky FLUSH SET a 1 FSET a(x) x*x UNSET a CLEAR-OMIT-CONTEXT PUSH-OMIT-CONTEXT POP-OMIT-CONTEXT BANNER wow DEBUG +x DEBUG -x DUMP $ EXIT 0 PRESERVE i ../tests/runtest.rem(2): shell(): RUN disabled ../tests/runinc.rem(1): shell(): RUN disabled ../tests/runinc.rem(3): shell(): RUN disabled No reminders. %!PS-Adobe-2.0 %%DocumentFonts: Helvetica Helvetica-BoldOblique %%Creator: Rem2PS %%Pages: (atend) %%Orientation: Landscape %%EndComments % This file was produced by Remind and Rem2PS, written by % Dianne Skoll. % Remind and Rem2PS are Copyright 1992-1997 Dianne Skoll. /ISOLatin1Encoding where { pop save true }{ false } ifelse /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] def { restore } if /reencodeISO { %def findfont dup length dict begin { 1 index /FID ne { def }{ pop pop } ifelse } forall /Encoding ISOLatin1Encoding def currentdict end definefont pop } bind def /copyFont { %def findfont dup length dict begin { 1 index /FID ne { def } { pop pop } ifelse } forall currentdict end definefont pop } bind def % L - Draw a line /L { newpath moveto lineto stroke } bind def % string1 string2 strcat string % Function: Concatenates two strings together. /strcat { 2 copy length exch length add string dup 4 2 roll 2 index 0 3 index putinterval exch length exch putinterval } bind def % string doheading /doheading { /monthyr exch def /TitleFont findfont TitleSize scalefont setfont monthyr stringwidth /hgt exch def 2 div MaxX MinX add 2 div exch sub /x exch def MaxY Border sub TitleSize sub /y exch def newpath x y moveto monthyr show newpath x y moveto monthyr false charpath flattenpath pathbbox pop pop Border sub /y exch def pop MinX y MaxX y L /topy y def /HeadFont findfont HeadSize scalefont setfont % Do the days of the week MaxX MinX sub 7 div /xincr exch def /x MinX def [(Sunday) (Monday) (Tuesday) (Wednesday) (Thursday) (Friday) (Saturday)] { HeadSize x y HeadSize 2 mul sub x xincr add y CenterText x xincr add /x exch def } forall y HeadSize 2 mul sub /y exch def MinX y MaxX y L /ytop y def /ymin y def } def /CenterText { /maxy exch def /maxx exch def /miny exch def /minx exch def /sz exch def /str exch def str stringwidth pop 2 div maxx minx add 2 div exch sub sz 2 div maxy miny add 2 div exch sub moveto str show } def % Variables: % curline - a string holding the current line % y - current y pos % yincr - increment to next line % xleft - left margin % width - max width. % EnterOneWord - given a word, enter it into the box. % string EnterOneWord /EnterOneWord { { EnterOneWordAux {exit} if } loop } bind def % EnterOneWordAux - if the word fits, enter it into box and return true. % If it doesn't fit, put as much as will fit and return the string and false. /EnterOneWordAux { /word exch def /tmpline curline word strcat def tmpline stringwidth pop width gt {MoveToNewLine} {/curline tmpline ( ) strcat def /word () def} ifelse word () eq {true} {word false} ifelse } bind def % MoveToNewLine - move to a new line, resetting word as appropriate /MoveToNewLine { curline () ne {newpath xleft y moveto curline show /curline () def /y y yincr add def} {ChopWord} ifelse } bind def % ChopWord - word won't fit. Chop it and find biggest piece that will fit /ChopWord { /curline () def /len word length def /Fcount len 1 sub def { word 0 Fcount getinterval stringwidth pop width le {exit} if /Fcount Fcount 1 sub def } loop % Got the count. Display it and reset word newpath xleft y moveto word 0 Fcount getinterval show /y y yincr add def /word word Fcount len Fcount sub getinterval def } bind def /FinishFormatting { word () ne {newpath xleft y moveto word show /word () def /curline () def /y y yincr add def} {curline () ne {newpath xleft y moveto curline show /word () def /curline () def /y y yincr add def} if} ifelse } bind def % FillBoxWithText - fill a box with text % text-array xleft width yincr y FillBoxWithText new-y % Returns the new Y-coordinate. /FillBoxWithText { /y exch def /yincr exch def /width exch def /xleft exch def /curline () def % The last two strings in the word array are actually the PostScript % code to execute before and after the entry is printed. dup dup length 1 sub get exch dup dup length 2 sub get dup length 0 gt {cvx exec} {pop} ifelse dup length 2 sub 0 exch getinterval {EnterOneWord} forall FinishFormatting dup length 0 gt {cvx exec} {pop} ifelse y } bind def % Variables for calendar boxes: % ytop - current top position % ymin - minimum y reached for current row % border ytop xleft width textarray daynum DoCalBox ybot % Do the entries for one calendar box. Returns lowest Y-coordinate reached /DoCalBox { /daynum exch def /textarr exch def /wid exch def /xl exch def /yt exch def /border exch def % Do the day number /DayFont findfont DaySize scalefont setfont xl wid add border sub daynum stringwidth pop sub yt border sub DaySize sub moveto daynum show % Do the text entries. Precharge the stack with current y pos. /ycur yt border sub DaySize sub DaySize sub 2 add def /EntryFont findfont EntrySize scalefont setfont ycur textarr { exch 2 sub /ycur exch def xl border add wid border sub border sub EntrySize 2 add neg ycur FillBoxWithText } forall } bind def 2 setlinecap % Define a default PreCal procedure /PreCal { pop pop } bind def /HeadFont /Helvetica copyFont /SmallFont /Helvetica copyFont /DayFont /Helvetica-BoldOblique copyFont /EntryFont /Helvetica copyFont /TitleFont /Helvetica copyFont /HeadSize 14 def /DaySize 14 def /EntrySize 8 def /TitleSize 14 def /XSIZE 612 def /MinX 36 def /MinY 36 def /MaxX 756 def /MaxY 576 def /Border 6 def /LineWidth 1 def 1 setlinewidth /SmallFont findfont /FontInfo get /isFixedPitch get {/SmallString (WW ) def} {/SmallString (WW) def} ifelse %%EndProlog %%Page: Aug09 1 90 rotate 0 XSIZE neg translate /SAVESTATE save def (August) (2009) PreCal SAVESTATE restore (August 2009) doheading /MinBoxSize ytop MinY sub 6 div def /ysmalltop ytop def /CAL1 { Border ytop 6 xincr mul MinX add xincr [ ] (1) DoCalBox /y exch def y ymin lt {/ymin y def} if } def 1 setgray CAL1 0 setgray /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /SAVESTATE save def 6 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /ytop ylast def CAL1 /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /CAL2 { Border ytop 0 xincr mul MinX add xincr [ ] (2) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL3 { Border ytop 1 xincr mul MinX add xincr [ ] (3) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL4 { Border ytop 2 xincr mul MinX add xincr [ ] (4) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL5 { Border ytop 3 xincr mul MinX add xincr [ ] (5) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL6 { Border ytop 4 xincr mul MinX add xincr [ ] (6) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL7 { Border ytop 5 xincr mul MinX add xincr [ ] (7) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL8 { Border ytop 6 xincr mul MinX add xincr [ ] (8) DoCalBox /y exch def y ymin lt {/ymin y def} if } def 1 setgray CAL2 CAL3 CAL4 CAL5 CAL6 CAL7 CAL8 0 setgray /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /SAVESTATE save def 0 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 1 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 2 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 0.8 setrgbcolor fill 0.0 setgray (First-Bit-Of-PS) (Second-Bit-Of-PS) (Third-Bit-Of-PS) (Fourth-Bit-Of-PS) SAVESTATE restore /SAVESTATE save def 3 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 1 setrgbcolor fill 0.0 setgray gsave 0 setgray newpath Border DaySize 2 div add BoxHeight Border sub DaySize 2 div sub DaySize 2 div 0 360 arc closepath stroke Border DaySize 2 div add DaySize 2 div add Border add BoxHeight border sub DaySize 2 div sub DaySize 2 div sub moveto /EntryFont findfont EntrySize scalefont setfont (20:56) show grestore SAVESTATE restore /SAVESTATE save def 4 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 5 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 6 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /ytop ylast def CAL2 CAL3 CAL4 CAL5 CAL6 CAL7 CAL8 /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /CAL9 { Border ytop 0 xincr mul MinX add xincr [ ] (9) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL10 { Border ytop 1 xincr mul MinX add xincr [ ] (10) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL11 { Border ytop 2 xincr mul MinX add xincr [ ] (11) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL12 { Border ytop 3 xincr mul MinX add xincr [ ] (12) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL13 { Border ytop 4 xincr mul MinX add xincr [ ] (13) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL14 { Border ytop 5 xincr mul MinX add xincr [ ] (14) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL15 { Border ytop 6 xincr mul MinX add xincr [ ] (15) DoCalBox /y exch def y ymin lt {/ymin y def} if } def 1 setgray CAL9 CAL10 CAL11 CAL12 CAL13 CAL14 CAL15 0 setgray /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /SAVESTATE save def 0 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 1 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 2 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 3 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 4 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 1 setrgbcolor fill 0.0 setgray gsave 0 setgray newpath Border DaySize 2 div add BoxHeight Border sub DaySize 2 div sub DaySize 2 div 0 360 arc closepath stroke newpath Border DaySize 2 div add BoxHeight Border sub DaySize 2 div sub DaySize 2 div 270 90 arc closepath fill Border DaySize 2 div add DaySize 2 div add Border add BoxHeight border sub DaySize 2 div sub DaySize 2 div sub moveto /EntryFont findfont EntrySize scalefont setfont (14:56) show grestore SAVESTATE restore /SAVESTATE save def 5 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 6 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /ytop ylast def CAL9 CAL10 CAL11 CAL12 CAL13 CAL14 CAL15 /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /CAL16 { Border ytop 0 xincr mul MinX add xincr [ ] (16) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL17 { Border ytop 1 xincr mul MinX add xincr [ ] (17) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL18 { Border ytop 2 xincr mul MinX add xincr [ ] (18) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL19 { Border ytop 3 xincr mul MinX add xincr [ ] (19) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL20 { Border ytop 4 xincr mul MinX add xincr [ ] (20) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL21 { Border ytop 5 xincr mul MinX add xincr [ ] (21) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL22 { Border ytop 6 xincr mul MinX add xincr [ ] (22) DoCalBox /y exch def y ymin lt {/ymin y def} if } def 1 setgray CAL16 CAL17 CAL18 CAL19 CAL20 CAL21 CAL22 0 setgray /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /SAVESTATE save def 0 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 1 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 2 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 3 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 4 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 1 setrgbcolor fill 0.0 setgray gsave 0 setgray newpath Border DaySize 2 div add BoxHeight Border sub DaySize 2 div sub DaySize 2 div 0 360 arc closepath fill Border DaySize 2 div add DaySize 2 div add Border add BoxHeight border sub DaySize 2 div sub DaySize 2 div sub moveto /EntryFont findfont EntrySize scalefont setfont (06:02) show grestore SAVESTATE restore /SAVESTATE save def 5 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 6 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /ytop ylast def CAL16 CAL17 CAL18 CAL19 CAL20 CAL21 CAL22 /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /CAL23 { Border ytop 0 xincr mul MinX add xincr [ ] (23) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL24 { Border ytop 1 xincr mul MinX add xincr [ ] (24) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL25 { Border ytop 2 xincr mul MinX add xincr [ ] (25) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL26 { Border ytop 3 xincr mul MinX add xincr [ ] (26) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL27 { Border ytop 4 xincr mul MinX add xincr [ ] (27) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL28 { Border ytop 5 xincr mul MinX add xincr [ ] (28) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL29 { Border ytop 6 xincr mul MinX add xincr [ ] (29) DoCalBox /y exch def y ymin lt {/ymin y def} if } def 1 setgray CAL23 CAL24 CAL25 CAL26 CAL27 CAL28 CAL29 0 setgray /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /SAVESTATE save def 0 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 1 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 2 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 3 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 4 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 1 setrgbcolor fill 0.0 setgray gsave 0 setgray newpath Border DaySize 2 div add BoxHeight Border sub DaySize 2 div sub DaySize 2 div 0 360 arc closepath stroke newpath Border DaySize 2 div add BoxHeight Border sub DaySize 2 div sub DaySize 2 div 90 270 arc closepath fill Border DaySize 2 div add DaySize 2 div add Border add BoxHeight border sub DaySize 2 div sub DaySize 2 div sub moveto /EntryFont findfont EntrySize scalefont setfont (07:42) show grestore SAVESTATE restore /SAVESTATE save def 5 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 0.8 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 6 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 1 0.8 setrgbcolor fill 0.0 setgray SAVESTATE restore /ytop ylast def CAL23 CAL24 CAL25 CAL26 CAL27 CAL28 CAL29 /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /CAL30 { Border ytop 0 xincr mul MinX add xincr [ ] (30) DoCalBox /y exch def y ymin lt {/ymin y def} if } def /CAL31 { Border ytop 1 xincr mul MinX add xincr [ ] (31) DoCalBox /y exch def y ymin lt {/ymin y def} if } def 1 setgray CAL30 CAL31 0 setgray /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /SAVESTATE save def 0 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 0.8 0.8 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /SAVESTATE save def 1 xincr mul MinX add ytop translate /BoxWidth xincr def /BoxHeight ylast ytop sub def /InBoxHeight BoxHeight border sub DaySize sub DaySize sub 2 add EntrySize add def /_A LineWidth 2 div def _A _A moveto BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto _A BoxHeight _A sub lineto closepath 1 1 1 setrgbcolor fill 0.0 setgray SAVESTATE restore /ytop ylast def CAL30 CAL31 /y ytop MinBoxSize sub def y ymin lt {/ymin y def} if MinX ymin MaxX ymin L /ylast ytop def /ytop ymin def /ysmallbot ylast def /ysmall1 ysmalltop def /ysmall2 ysmallbot def 0 xincr mul MinX add ymin 0 xincr mul MinX add topy L 1 xincr mul MinX add ymin 1 xincr mul MinX add topy L 2 xincr mul MinX add ymin 2 xincr mul MinX add topy L 3 xincr mul MinX add ymin 3 xincr mul MinX add topy L 4 xincr mul MinX add ymin 4 xincr mul MinX add topy L 5 xincr mul MinX add ymin 5 xincr mul MinX add topy L 6 xincr mul MinX add ymin 6 xincr mul MinX add topy L 7 xincr mul MinX add ymin 7 xincr mul MinX add topy L /SmallFontSize MinBoxSize Border sub Border sub 8 div 2 sub def /SmallFont findfont setfont SmallString stringwidth pop /SmallWidth exch def SmallWidth 7 mul xincr Border sub Border sub exch div /tmp exch def tmp SmallFontSize lt {/SmallFontSize tmp def} if /SmallFont findfont SmallFontSize scalefont setfont SmallString stringwidth pop /SmallWidth exch def gsave 0 xincr mul MinX add ysmall1 translate SmallWidth 7 mul (July) stringwidth pop sub 2 div Border add Border neg SmallFontSize sub moveto (July) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (S) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (M) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (T) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (W) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (T) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (F) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (S) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (1) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (2) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (3) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (4) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (5) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (6) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (7) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (8) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (9) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (10) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (11) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (12) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (13) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (14) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (15) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (16) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (17) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (18) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (19) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (20) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (21) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (22) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (23) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (24) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (25) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (26) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (27) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (28) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (29) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (30) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (31) show grestore /SmallFontSize MinBoxSize Border sub Border sub 8 div 2 sub def /SmallFont findfont setfont SmallString stringwidth pop /SmallWidth exch def SmallWidth 7 mul xincr Border sub Border sub exch div /tmp exch def tmp SmallFontSize lt {/SmallFontSize tmp def} if /SmallFont findfont SmallFontSize scalefont setfont SmallString stringwidth pop /SmallWidth exch def gsave 6 xincr mul MinX add ysmall2 translate SmallWidth 7 mul (September) stringwidth pop sub 2 div Border add Border neg SmallFontSize sub moveto (September) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (S) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (M) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (T) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (W) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (T) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (F) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize sub 2 sub moveto (S) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (1) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (2) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (3) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (4) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 2 mul sub moveto (5) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (6) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (7) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (8) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (9) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (10) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (11) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 3 mul sub moveto (12) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (13) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (14) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (15) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (16) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (17) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (18) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 4 mul sub moveto (19) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (20) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (21) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (22) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (23) show Border 4 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (24) show Border 5 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (25) show Border 6 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 5 mul sub moveto (26) show Border 0 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (27) show Border 1 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (28) show Border 2 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (29) show Border 3 SmallWidth mul add Border neg SmallFontSize sub SmallFontSize 2 add 6 mul sub moveto (30) show grestore showpage %%Trailer %%Pages: 1 Reminders for Sunday, 1st January, 2012: 1 Reminders for Sunday, 1st January, 2012: 9am: Should show up 10am: Should show up 2 remind-03.01.15/tests/test.rem0000644000076400007640000002117212555504121014172 0ustar dfsdfs# Test file for REMIND # # Use this file to test the date calculation routines # of the REMIND program by typing: # # ./test-rem # From WITHIN Remind source directory! # Don't evaluate SATISFY expressions if reminder has expired REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie # bad AT REM AT 0:00 0:01 0:02 MSG foo REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())] fset _h(x, y) trigger(hebdate(x,y)) [_h(1, "Tishrey")] MSG Rosh Hashana 1 [_h(2, "Tishrey")] MSG Rosh Hashana 2 [_h(3, "Tishrey")] MSG Tzom Gedalia [_h(10, "Tishrey")] MSG Yom Kippur [_h(15, "Tishrey")] MSG Sukkot 1 [_h(25, "Kislev")] MSG Channuka [_h(10, "Tevet")] MSG Asara B'Tevet [_h(15, "Shvat")] MSG Tu B'Shvat [_h(15, "Adar A")] MSG Purim Katan [_h(14, "Adar")] MSG Purim [_h(15, "Nisan")] MSG Pesach [_h(27, "Nisan")] MSG Yom HaShoah [_h(4, "Iyar")] MSG Yom HaZikaron [_h(5, "Iyar")] MSG Yom Ha'atzmaut [_h(28, "Iyar")] MSG Yom Yerushalayim [_h(6, "Sivan")] MSG Shavuot [_h(9, "Av")] MSG Tish'a B'Av # Test some jahrzeit cases fset _i(x,y,z,a) trigger(hebdate(x,y,z,a)) [_i(30, "Heshvan", today(), 5759)] MSG Complete-Complete [_i(30, "Heshvan", today(), 5760)] MSG Complete-Defective [_i(30, "Heshvan", today(), 5761)] MSG Illegal [_i(30, "Kislev", today(), 5759)] MSG Complete-Complete [_i(30, "Kislev", today(), 5760)] MSG Complete-Defective [_i(30, "Kislev", today(), 5761)] MSG Illegal [_i(30, "Adar A", today(), 5755)] MSG Leap [_i(30, "Adar A", today(), 5756)] MSG Illegal [_i(29, "Adar A", today(), 5755)] MSG Leap [_i(29, "Adar A", today(), 5756)] MSG Illegal # This causes a parse error on version 03.01.01 REM 1990-01-01 SATISFY 1 # Test each possible case of the basic reminders. REM MSG Every Day REM 18 MSG Every 18th REM 15 MSG Every 15th REM Feb MSG February REM Jan MSG January REM March MSG March REM 13 Jan MSG 13 Jan REM 15 Feb MSG 15 Feb REM 28 Feb MSG 28 Feb REM 29 Feb MSG 29 Feb REM 5 Mar MSG 5 Mar REM 1990 MSG 1990 REM 1991 MSG 1991 REM 1992 MSG 1991 REM 1 1990 MSG 1 1990 REM 29 1991 MSG 29 1991 REM 29 1992 MSG 29 1992 REM 16 1991 MSG 16 1991 REM Jan 1990 MSG Jan 1990 REM Feb 1991 MSG Feb 1991 REM Dec 1991 MSG Dec 1991 REM May 1992 MSG May 1992 REM 1 Jan 1991 MSG 1 Jan 1991 REM 16 Feb 1991 MSG 16 Feb 1991 REM 29 Dec 1992 MSG 29 Dec 1992 REM Sun MSG Sun REM Fri Sat Tue MSG Fri Sat Tue REM Sun 16 MSG Sun 16 REM Mon Tue Wed Thu Fri 1 MSG Mon Tue Wed Thu Fri 1 REM Sun Feb MSG Sun Feb REM Mon Tue March MSG Mon Tue March REM Sun 16 Feb MSG Sun 16 Feb REM Mon Tue 10 March MSG Mon Tue 10 March REM Sat Sun 1991 MSG Sat Sun 1991 REM Mon Tue 1992 MSG Mon Tue 1992 REM Sun 16 1991 MSG Sun 16 1991 REM Mon Tue Wed Thu Fri 1 1992 MSG Mon Tue Wed Thu Fri 1 1992 REM Mon Feb 1991 MSG Mon Feb 1991 REM Tue Jan 1992 MSG Tue Jan 1992 REM Sun Mon 16 Feb 1991 MSG Sun Mon 16 Feb 1991 REM Tue 28 Jan 1992 MSG Tue 28 Jan 1992 # Try some Backs CLEAR-OMIT-CONTEXT REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun OMIT 28 Feb REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun (28 Feb omitted) REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun (28 Feb omitted) CLEAR-OMIT-CONTEXT # Try out UNTIL REM Wed UNTIL 21 Feb 1991 MSG Wed UNTIL 21 Feb 1991 # Try playing with the OMIT context OMIT 28 Feb 1991 REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted) REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted) REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted) REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted) REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted) PUSH-OMIT-CONTEXT CLEAR-OMIT-CONTEXT REM 1 Mar -1 MSG 1 mar -1 REM 1 Mar --1 MSG 1 mar --1 REM 28 Feb BEFORE MSG 28 Feb BEFORE REM 28 Feb SKIP MSG 28 Feb SKIP REM 28 Feb AFTER MSG 28 Feb AFTER POP-OMIT-CONTEXT REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted) REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted) REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted) REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted) REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted) REM 13 March 1991 *1 UNTIL 19 March 1991 MSG 13-19 Mar 91 # Test BACK CLEAR-OMIT-CONTEXT REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 OMIT 17 Feb 1991 REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 (17Feb91 omitted) REM 18 Feb 1991 ++1 MSG 18 Feb 1991 ++1 (17Feb91 omitted) CLEAR-OMIT-CONTEXT # Test the scanfrom clause REM Fri SATISFY 1 OMIT [trigger(trigdate())] REM Fri after MSG 23 Feb 1991 CLEAR-OMIT-CONTEXT REM Fri SCANFROM [trigger(today()-7)] SATISFY 1 OMIT [trigger(trigdate())] REM Fri after MSG 16 Feb 1991 CLEAR-OMIT-CONTEXT # Test omitfunc fset _ofunc(x) (day(x) < 7 || day(x) % 2) REM 1 March OMITFUNC _ofunc AFTER MSG OmitFunc Test REM 8 March OMITFUNC _ofunc -1 MSG OmitFunc Test 2 # omitfunc ignores local/global omits fset _ofunc(x) 0 OMIT 1 March OMIT 2 March 1991 REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March REM 1 March OMIT Sun AFTER MSG Should trigger 4 March # Test shorthand reminders REM 1991-02-28 MSG Feb 28 REM 1991/02/28@14:45 MSG Feb 28 REM Wed UNTIL 1991-01-01 MSG Expired REM Wed SCANFROM 1991-02-26 MSG SCANFROM set a000 abs(1) set a001 abs(-1) set a002 asc("foo") set a003 baseyr() set a004 char(66,55,66,77,66) set a005 choose(3, "foo", "bar", "baz", "blech") set a006 coerce("string", 1) set a007 coerce("string", today()) set a008 coerce("string", 11:44) set a009 coerce("int", "badnews") set a010 coerce("int", "12") set a011 coerce("int", 11:44) set a012 coerce("int", today()) set a013 date(1992, 2, 2) set a014 date(1993, 2, 29) set a015 day(today()) set a016 daysinmon(2, 1991) set a017 daysinmon(2, 1992) set a018 defined("a017") set a019 defined("a019") set a020 filename() set a021 getenv("TEST_GETENV") set a022 hour(11:22) set a023 iif(1, 1, 0) set a024 iif(0, 1, 0) set a025 index("barfoobar", "foo") set a026 index("barfoobar", "bar", 2) set a027 isleap(today()) set a028 isleap(1992) omit [trigger(today())] set a030 isomitted(today()) clear set a029 isomitted(today()) set a031 lower("FOOBARBAZ") set a032 max(1, 2, 34, 1, 3) set a033 max("foo", "bar", "baz") set a034 max(today(), today()+1, today()-1) set a035 min(1, 2, 34, 1, 3) set a036 min("foo", "bar", "baz") set a037 min(today(), today()+1, today()-1) set a038 minute(11:33) set a039 mon(today()) set a040 monnum(today()) set a041 ord(3) set a042 ord(4) set a043 ostype() set a044 plural(2) set a045 plural(2, "ies") set a046 plural(2, "y", "ies") set a047 sgn(-2) set a048 shell("echo foo") set a049 strlen("sadjflkhsldkfhsdlfjhk") set a050 substr(a049, 2) set a051 substr(a050, 2, 6) set a052 time(1+2, 3+4) rem 10 jan 1992 AT 11:22 CAL set a053 trigdate() set a054 trigtime() set a055 trigvalid() set a056 upper("sdfjhsdf ksjdfh kjsdfh ksjdfh") set a057 value("a05"+"6") set a058 version() set a059 wkday(today()) set a060 wkdaynum(today()) set a061 year(today()) set a062 1+2*(3+4-(5*7/2)) set a063 1>=2 set a064 1<2 || 3 > 4 set a065 1 && 1 set a066 !a065 set a067 typeof(2) set a068 typeof("foo") set a069 typeof(11:33) set a070 typeof(today()) fset g(x,y) max(x,y) fset h(x,y) min(g(x+y, x*y), g(x-y, x/y)) set a071 g(1, 2) set a072 h(2, 3) set a073 h("foo", 11:33) set a074 dosubst("%a %b %c %d %e %f %g %h", '1992/5/5') msg [a074]% set a075 dosubst("%i %j %k %l %m %n %o %p", '1992/5/5') msg [a075]% set a076 dosubst("%q %r %s %t %u %v %w %x", '1992/5/5') msg [a076]% set a074 dosubst("%*a %*b %*c %*d %*e %*f %*g %*h", '1992/5/5') msg [a074]% set a075 dosubst("%*i %*j %*k %*l %*m %*n %*o %*p", '1992/5/5') msg [a075]% set a076 dosubst("%*q %*r %*s %*t %*u %*v %*w %*x", '1992/5/5') msg [a076]% set a077 dosubst("%*y %*z", '1992/5/5') msg [a077]% set a074 dosubst("%A %B %C %D %E %F %G %H", '1992/5/5') msg [a074]% set a075 dosubst("%I %J %K %L %M %N %O %P", '1992/5/5') msg [a075]% set a076 dosubst("%Q %R %S %T %U %V %W %X", '1992/5/5') msg [a076]% set a077 dosubst("%Y %Z", '1992/5/5') msg [a077]% set a074 dosubst("%*A %*B %*C %*D %*E %*F %*G %*H", '1992/5/5') msg [a074]% set a075 dosubst("%*I %*J %*K %*L %*M %*N %*O %*P", '1992/5/5') msg [a075]% set a076 dosubst("%*Q %*R %*S %*T %*U %*V %*W %*X", '1992/5/5') msg [a076]% set a077 dosubst("%*Y %*Z", '1992/5/5') msg [a077]% set a078 easterdate(today()) set a079 easterdate(1992) set a080 easterdate(1995) set a081 "" OMIT 1991-03-11 set a082 slide('1991-03-01', 7, "Sat", "Sun") set a083 slide('1991-04-01', -7, "Sat") set a084 nonomitted('1991-03-01', '1991-03-13', "Sat", "Sun") set a085 nonomitted('1991-03-24', '1991-04-01', "Sat") dump dump $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa OMIT 2010-09-03 THROUGH 2010-09-15 OMIT December 25 MSG X # Next should give a parse error OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal OMIT DUMP __EOF__ REM This line should not even be seen And you can put whatever you like here. [+f=asdfasdasde3ir0a] remind-03.01.15/tests/test2.rem0000644000076400007640000000202711057403122014245 0ustar dfsdfs# Make things sane set $TimeSep ":" set $DateSep "/" set $LatDeg 45 set $LatMin 24 set $LatSec 0 set $Location "Ottawa" set $LongDeg 75 set $LongMin 39 set $LongSec 0 clear-omit-context omit 14 aug # Test the SPECIAL COLOR escapes REM WED +2 SPECIAL COLOR 0 0 255 %"Blue Wednesday%" is %b REM THU SPECIAL COLOR 255 0 0 Red Thursday # Test SPECIAL SHADE REM FRI SPECIAL SHADE 0 255 0 # Test SPECIAL MOON REM 12 AUG SPECIAL MOON 0 # Test nonomitted REM MSG [nonomitted('2007-08-01', today())] NonOmit-1 REM MSG [nonomitted('2007-08-01', today(), "Sat", "Sun")] NonOmit-2 # Test SPECIAL COLOR with an AT clause REM 20 AUG AT 13:45 SPECIAL COLOR 6 7 8 Mooo! # Test SPECIAL PostScript with and without AT clause REM 21 AUG AT 1:55 SPECIAL PostScript (wookie) show REM 22 AUG SPECIAL PostScript (cabbage) show # Test a random SPECIAL with and without AT REM 23 AUG AT 16:44 SPECIAL blort snoo glup REM 24 AUG SPECIAL blort gulp wookie # Bug discovered by Paul Pelzl OMIT 13 August REM 6 August 2007 *7 SKIP SATISFY [1] MSG Blort remind-03.01.15/tests/test3.rem0000644000076400007640000000144711057403122014253 0ustar dfsdfsREM 1 AT 11:00 MSG Wookie REM 1 AT 12:00 MSG Cookie REM 1 AT 13:00 MSG Snookie REM 1 AT 11:00 DURATION 0:45 MSG Lettuce REM 1 AT 12:00 DURATION 0:45 MSG Cabbage REM 1 AT 13:00 DURATION 0:45 MSG Tomato REM 1 AT 11:00 DURATION 1:45 MSG Apple REM 1 AT 12:00 DURATION 2:45 MSG Pear REM 1 AT 13:00 DURATION 3:45 MSG Grape REM 1 AT 11:00 DURATION 14:45 MSG Green REM 1 AT 12:00 DURATION 14:45 MSG Blue REM 1 AT 13:00 DURATION 14:45 MSG Red REM 1 AT 11:00 DURATION 24:45 MSG Yellow REM 1 AT 12:00 DURATION 24:45 MSG Orange REM 1 AT 13:00 DURATION 24:45 MSG Magenta REM 1 AT 11:00 DURATION 36:45 MSG Purple REM 1 AT 12:00 DURATION 36:45 MSG Black REM 1 AT 13:00 DURATION 36:45 MSG Brown REM 1 AT 11:00 DURATION 48:45 MSG Sad REM 1 AT 12:00 DURATION 48:45 MSG Happy REM 1 AT 13:00 DURATION 48:45 MSG Strange remind-03.01.15/tests/tstlang.rem0000644000076400007640000001073012514120342014657 0ustar dfsdfs#!remind -rq # --------------------------------------------------------------------------- # # TSTLANG.REM # # Use this file to test new language headers you may want to create. # Usage: remind -rq tstlang.rem # # Don't run it within about 2 hours of midnight (ie, between 10pm and 2am) # # Use the output to verify your translations. # # This file is part of REMIND. # Copyright (C) 1992-1997 Dianne Skoll # Copyright (C) 1999-2000 Roaring Penguin Software Inc. # # --------------------------------------------------------------------------- if version()<"03.00.08" errmsg % errmsg This file only works with Remind version 03.00.08 and later - aborting exit endif if !$RunOff || !$DontQueue || $DontTrigAts errmsg % errmsg Please run [filename()] with the -q and -r options, but% errmsg not the -a option. exit endif # Set up a few useful definitions fset show(x) "%%" + x + " yields: " + char(34) + "%" + x + char(34) + "% and %%*" + x + " yields: " + char(34) + "%*" + x + char(34) + "%" set a trigger(today()+2) + " ++2" set l language() set tt now()+134 set tu now()-134 set d a + " at " + tt set e a + " at " + tu msg The above is the default banner for the [l] language. msg The following are the two-day-in-advance substitutions:% [a] msg [show("a")] [a] msg [show("b")] [a] msg [show("c")] [a] msg [show("d")] [a] msg [show("e")] [a] msg [show("f")] [a] msg [show("g")] [a] msg [show("h")] [a] msg [show("i")] [a] msg [show("j")] [a] msg [show("k")] [a] msg [show("l")] [a] msg [show("m")] [a] msg [show("n")] [a] msg [show("o")] [a] msg [show("p")] [a] msg [show("q")] [a] msg [show("r")] [a] msg [show("s")] [a] msg [show("t")] [a] msg [show("u")] [a] msg [show("v")] [a] msg [show("w")] [a] msg [show("x")] [a] msg [show("y")] [a] msg [show("z")] msg %_%_The following are the one-day-in-advance substitutions:% set a trigger(today()+1) + " ++1" set d a + " at " + tt set e a + " at " + tu [a] msg [show("a")] [a] msg [show("b")] [a] msg [show("c")] [a] msg [show("d")] [a] msg [show("e")] [a] msg [show("f")] [a] msg [show("g")] [a] msg [show("h")] [a] msg [show("i")] [a] msg [show("j")] [a] msg [show("k")] [a] msg [show("l")] [a] msg [show("m")] [a] msg [show("n")] [a] msg [show("o")] [a] msg [show("p")] [a] msg [show("q")] [a] msg [show("r")] [a] msg [show("s")] [a] msg [show("t")] [a] msg [show("u")] [a] msg [show("v")] [a] msg [show("w")] [a] msg [show("x")] [a] msg [show("y")] [a] msg [show("z")] msg %_%_The following are the current-day substitutions:% set a trigger(today()) set d a + " at " + tt set e a + " at " + tu [a] msg [show("a")] [a] msg [show("b")] [a] msg [show("c")] [a] msg [show("d")] [a] msg [show("e")] [a] msg [show("f")] [a] msg [show("g")] [a] msg [show("h")] [a] msg [show("i")] [a] msg [show("j")] [a] msg [show("k")] [a] msg [show("l")] [a] msg [show("m")] [a] msg [show("n")] [a] msg [show("o")] [a] msg [show("p")] [a] msg [show("q")] [a] msg [show("r")] [a] msg [show("s")] [a] msg [show("t")] [a] msg [show("u")] [a] msg [show("v")] [a] msg [show("w")] [a] msg [show("x")] [a] msg [show("y")] [a] msg [show("z")] msg %_Time substititions for a time in the future:% [d] msg [show("1")] [d] msg [show("2")] [d] msg [show("3")] [d] msg [show("4")] [d] msg [show("5")] [d] msg [show("6")] [d] msg [show("7")] [d] msg [show("8")] [d] msg [show("9")] [d] msg [show("0")] [d] msg [show("!")] [d] msg [show("@")] [d] msg [show("#")] msg %_Time substititions for a time in the past:% [e] msg [show("1")] [e] msg [show("2")] [e] msg [show("3")] [e] msg [show("4")] [e] msg [show("5")] [e] msg [show("6")] [e] msg [show("7")] [e] msg [show("8")] [e] msg [show("9")] [e] msg [show("0")] [e] msg [show("!")] [e] msg [show("@")] [e] msg [show("#")] msg %_Time substititions for the current time:% set e a + " at " + now() [e] msg [show("1")] [e] msg [show("2")] [e] msg [show("3")] [e] msg [show("4")] [e] msg [show("5")] [e] msg [show("6")] [e] msg [show("7")] [e] msg [show("8")] [e] msg [show("9")] [e] msg [show("0")] [e] msg [show("!")] [e] msg [show("@")] [e] msg [show("#")] msg %_The following are the days of the week: fset showwd(x) "wkday("+x+") = " + wkday(x) + "%" msg [showwd(0)] msg [showwd(1)] msg [showwd(2)] msg [showwd(3)] msg [showwd(4)] msg [showwd(5)] msg [showwd(6)] msg %_The following are the months of the year: fset showmon(x) "mon("+x+") = "+mon(x)+"%" msg [showmon(1)] msg [showmon(2)] msg [showmon(3)] msg [showmon(4)] msg [showmon(5)] msg [showmon(6)] msg [showmon(7)] msg [showmon(8)] msg [showmon(9)] msg [showmon(10)] msg [showmon(11)] msg [showmon(12)] remind-03.01.15/unconfigure0000755000076400007640000000037011614325174013617 0ustar dfsdfs#!/bin/sh echo "Unconfiguring Remind..." echo rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile exit 0 remind-03.01.15/www/Makefile.in0000644000076400007640000000724712514120342014236 0ustar dfsdfs# Makefile.in for installing WWW server calendar scripts # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2007 by Roaring Penguin Software Inc. # The complete path to where the scripts actually live, as seen by # the UNIX operating system. SCRIPTDIR = /var/www/cgi-bin # Where the scripts live as seen by the web browser. CGIDIR = /cgi-bin # The complete path to the directory containing the HTML file "calendar.html". # This is a sample file containing links to all the scripts. This path # should be the path as seen by the UNIX operating system HTMLDIR = /var/www/remind # Where you stick images and CSS files, as seen by UNIX IMAGEDIR = /var/www/remind/resources # Where images are, as seen by web browers IMAGEBASE = /remind/resources # Set by configure - don't touch. srcdir=@srcdir@ prefix=@prefix@ exec_prefix=@exec_prefix@ mandir=@mandir@ bindir=@bindir@ datadir=@datadir@ datarootdir=@datarootdir@ # Where do Remind and Rem2PS executables live? REMIND = $(bindir)/remind REM2PS = $(bindir)/rem2ps # If your Web server requires CGI programs to have a .cgi suffix, use # the next line. Otherwise, comment it out CGISUFFIX=.cgi # Don't change stuff below here. # -------------------------------------------------------------------- # Construct a rotten mean nasty sed script to do the dirty work SEDSCRIPT = -e 's@%CGIDIR%@$(CGIDIR)@g' \ -e 's@%SCRIPTDIR%@$(SCRIPTDIR)@g' \ -e 's@%REMIND%@$(REMIND)@g' \ -e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \ -e 's@%REM2PS%@$(REM2PS)@g' \ -e 's@cal_dispatch@cal_dispatch$(CGISUFFIX)@g' \ -e 's@rem2html@rem2html$(CGISUFFIX)@g' SEDSCRIPT2 = -e 's@%CGIDIR%@$(CGIDIR)@g' \ -e 's@%SCRIPTDIR%@$(SCRIPTDIR)@g' \ -e 's@%REMIND%@$(REMIND)@g' \ -e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \ -e 's@%REM2PS%@$(REM2PS)@g' all: @echo "Edit the Makefile; then type 'make install' to install" @echo "the www server scripts." # OK, it's abominable. But it works... install: -mkdir -p $(DESTDIR)$(SCRIPTDIR) -mkdir -p $(DESTDIR)$(HTMLDIR) cp calps hebdate hebps hebhtml moon sunrise sunset $(DESTDIR)$(SCRIPTDIR) sed $(SEDSCRIPT) < cal_dispatch-DIST > $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX) sed $(SEDSCRIPT) < hebdate.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/hebdate.rem sed $(SEDSCRIPT) < moon.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/moon.rem sed $(SEDSCRIPT) < sunrise.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/sunrise.rem sed $(SEDSCRIPT) < sunset.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/sunset.rem sed $(SEDSCRIPT) < calendar.html-DIST > $(DESTDIR)$(HTMLDIR)/calendar.html sed $(SEDSCRIPT) < hebhtml > $(DESTDIR)$(SCRIPTDIR)/hebhtml sed $(SEDSCRIPT2) < rem2html > $(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX) chmod 644 $(DESTDIR)$(SCRIPTDIR)/sunrise.rem chmod 644 $(DESTDIR)$(SCRIPTDIR)/moon.rem chmod 644 $(DESTDIR)$(SCRIPTDIR)/hebdate.rem chmod 644 $(DESTDIR)$(SCRIPTDIR)/sunset.rem chmod 644 $(DESTDIR)$(HTMLDIR)/calendar.html chmod 755 $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX) chmod 755 $(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX) chmod 755 $(DESTDIR)$(SCRIPTDIR)/calps $(DESTDIR)$(SCRIPTDIR)/hebdate \ $(DESTDIR)$(SCRIPTDIR)/hebps $(DESTDIR)$(SCRIPTDIR)/moon \ $(DESTDIR)$(SCRIPTDIR)/sunrise $(DESTDIR)$(SCRIPTDIR)/sunset \ $(DESTDIR)$(SCRIPTDIR)/hebhtml \ $(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX) -mkdir -p $(DESTDIR)$(IMAGEDIR) cp firstquarter.png fullmoon.png lastquarter.png newmoon.png rem-default.css $(DESTDIR)$(IMAGEDIR) chmod 644 $(DESTDIR)$(IMAGEDIR)/firstquarter.png \ $(DESTDIR)$(IMAGEDIR)/fullmoon.png \ $(DESTDIR)$(IMAGEDIR)/lastquarter.png \ $(DESTDIR)$(IMAGEDIR)/newmoon.png \ $(DESTDIR)$(IMAGEDIR)/rem-default.css remind-03.01.15/www/README0000644000076400007640000000311711057403122013042 0ustar dfsdfsREADME HTML Hebrew Calendar Server This is a rudimentary Hebrew calendar server for the WWW. It supplies local sunrise and sunset times, moon phases, upcoming Jewish holidays, and PostScript calendars. It only works under UNIX. I've only tested it with Linux running NCSA's httpd and Apache's httpd, but it should work on any UNIX web server. To install it, you need the Remind package, available via ftp from ftp://ftp.doe.carleton.ca/pub/remind-3.0. You should install Remind, setting the lattitude, longitude, location and time zone as appropriate for your machine. Once you have Remind installed, follow these steps to set up your WWW server: 1) Edit the Makefile in this directory. See the comments in the Makefile for details. 2) Edit the first line of "rem2html" to reflect the location of Perl on your system. (Oh yeah, you need Perl for the HTML Hebrew calendar...) 3) Type "make install" 4) Test it out. It will generate links of the form: http://www.your_server.com/your_cgi-bin/cal_dispatch?what where "what" is one of: sunrise -- show info about sunrise times. sunset -- show info about sunset times. hebdate -- show today's Hebrew date. calps -- get a blank PostScript calendar. moon -- show info about moon phases. hebps -- get a PostScript calendar with Jewish holidays. hebhtml -- get an HTML version of the above (requires Perl.) (Visit http://www.doe.carleton.ca/~dfs/ for previews.) All of these links will be set up in a sample HTML document called "calendar.html" and installed in the HTMLDIR you specified in the Makefile. 4) Enjoy! remind-03.01.15/www/README.rem2html0000644000076400007640000000051312514120342014567 0ustar dfsdfsREM2HTML -------- Rem2HTML is a Perl script that transforms the output of `remind -p ...' to HTML. Type `perl rem2html --help' for usage information. Typical usage: remind -p ~/.reminders | rem2html > file.html You may have to edit the "#!/usr/bin/perl" line to reflect the location of your Perl interpreter. -- Dianne Skoll remind-03.01.15/www/cal_dispatch-DIST0000644000076400007640000000250712514120342015265 0ustar dfsdfs#!/bin/sh # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. # CAL_DISPATCH -- Shell script for CGI directory to dispatch calendar # commands. ######################### # # Parameters for you to change # ######################### # Set DIR to the directory in which all the scripts live. They must all # be in the same directory. The scripts are: # cal_dispatch, cal_ps, hebdate, hebps, moon, sunrise and sunset. # In addition, the reminder files hebbg.ps, hebdate.rem, moon.rem, # sunrise.rem and sunset.rem must live in $DIR. DIR=%SCRIPTDIR% export DIR # Set REMIND to the full pathname of the Remind executable. REMIND=%REMIND% export REMIND # Set REM2PS to the full pathname of the rem2ps executable REM2PS=%REM2PS% export REM2PS ######################### # # Don't change anything after this. # ######################### if [ "$1" = "" ] ; then exit 0 fi case "$1" in sunrise) exec $DIR/sunrise ;; sunset) exec $DIR/sunset ;; hebdate) exec $DIR/hebdate ;; calps) exec $DIR/calps ;; moon) exec $DIR/moon ;; hebps) exec $DIR/hebps ;; hebhtml) if [ "$2" = "" -o "$3" = "" ] ; then exec $DIR/hebhtml else exec $DIR/hebhtml "$2" "$3" fi ;; esac exit 0 remind-03.01.15/www/calendar.html-DIST0000644000076400007640000000151111057403122015356 0ustar dfsdfs Remind Calendar Server

Remind Calendar Server

Sunrise Information

Sunset Information

Moon Phase Information

Blank PostScript Calendar (Approximately 20kB)

Today's Hebrew Date

PostScript Calendar with Jewish Holidays (Approximately 35 kB)

HTML Calendar with Jewish Holidays


Get the Remind software that provides this service.

remind-03.01.15/www/calps0000644000076400007640000000042612514120342013206 0ustar dfsdfs#!/bin/sh # PostScript calendar shell script # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. echo "Content-type: application/postscript" echo $REMIND -p /dev/null | $REM2PS -e -c3 -l exit 0 remind-03.01.15/www/firstquarter.png0000644000076400007640000000057312123136532015431 0ustar dfsdfsPNG  IHDRasBIT|d pHYsftEXtSoftwarewww.inkscape.org<IDAT81JAo b)hb<7V7Ig"FY5&$S.KTJ]cxD$xF[y h">}ưAiߤ?< &͈?o҈`1Tڨt LKG'2gH(#2}#zӂ)z-~v}Mo#"e/b*&Ǹ*&.Snj: { IENDB`remind-03.01.15/www/fullmoon.png0000644000076400007640000000047512123136525014534 0ustar dfsdfsPNG  IHDRasBIT|d pHYsftEXtSoftwarewww.inkscape.org<IDAT8ӱm0,hUZ&cF*"eeRyriCVHq|$T)e5#(T<[ ޓ|xŘoc$7qKx9&Q۝$6yuF6vqš ?s]j ' TJwT1%<</ 0Zog%:[&IENDB`remind-03.01.15/www/hebdate0000644000076400007640000000056512514120343013505 0ustar dfsdfs#!/bin/sh # Hebrew date shell script # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. echo Content-type: text/html echo "" cat < Hebrew date

Hebrew date

EOM $REMIND -arqh $DIR/hebdate.rem echo "" echo "" exit 0 remind-03.01.15/www/hebdate.rem-DIST0000644000076400007640000001333712514120343015031 0ustar dfsdfs# Hebrew date reminder file # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. BANNER % IF !$PSCAL FSET _hstr(x) HEBDAY(x) + " " + HEBMON(x) + ", " + HEBYEAR(x) FSET msgsuffix(x) "

" MSG The Hebrew date for today, %d %m, %y, is [_hstr(today())]. % MSG And the Hebrew date for tomorrow is [_hstr(today()+1)]. % fset msgprefix(x) iif($NumTrig==OldTrig, "

Upcoming Holidays

"+char(13,10),"") set oldtrig $numtrig ENDIF #JHOLS ########################################################################## # # # This portion of the file contains reminders for Jewish holidays. The # # dates were obtained from "The First Jewish Catalog" by Richard Siegel # # and Michael and Sharon Strassfeld, published by the Jewish Publication # # Society of America. The Reform version of the calendar was guessed # # at by Dianne Skoll based on experience. Additional corrections were # # made from the paper "Calendrical Calculations" by Nachum Dershowitz # # and Edward M. Reingold. Any further corrections are welcome. # # # ########################################################################## # --- HERE ARE THE JEWISH HOLIDAYS --- # Set the variable InIsrael to 1 if you live in Israel. Otherwise, # you get the Diaspora versions of Jewish holidays SET InIsrael 0 # Set the variable Reform to 1 if you want the Reform version of the # Jewish calendar. Otherwise, you get the traditional version SET Reform 0 # Convenient function definition to save typing FSET _h(x, y) TRIGGER(HEBDATE(x,y)) FSET _h2(x, y) HEBDATE(x, y, TODAY()-7) FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, \ TRIGGER(_h2(x,y)), \ TRIGGER(_h2(x,y)+1)) # Default values in case InIsrael and Reform are not set SET InIsrael VALUE("InIsrael", 0) SET Reform VALUE("Reform", 0) [_h(1, "Tishrey")] ++12 MSG %"Rosh Hashana 1%" is %b. # No RH-2 or Tzom Gedalia in Reform IF !Reform [_h(2, "Tishrey")] ++12 MSG %"Rosh Hashana 2%" is %b. [_PastSat(3, "Tishrey")] ++12 MSG %"Tzom Gedalia%" is %b. ENDIF [_h(10, "Tishrey")] ++12 MSG %"Yom Kippur%" is %b. [_h(15, "Tishrey")] ++12 MSG %"Sukkot 1%" is %b. IF !InIsrael [_h(16, "Tishrey")] MSG %"Sukkot 2%" ENDIF [_h(21, "Tishrey")] ++12 MSG %"Hoshana Rabba%" is %b. [_h(22, "Tishrey")] ++12 MSG %"Shemini Atzeret%" is %b. IF InIsrael [_h(22, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b. ELSE [_h(23, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b. ENDIF # Because Kislev can change length, we must be more careful about Chanukah FSET _chan(x) TRIGGER(HEBDATE(24, "Kislev", today()-9)+x) [_chan(1)] ++12 MSG %"Chanukah 1%" is %b. [_chan(2)] MSG %"Chanukah 2%" [_chan(3)] MSG %"Chanukah 3%" [_chan(4)] MSG %"Chanukah 4%" [_chan(5)] MSG %"Chanukah 5%" [_chan(6)] MSG %"Chanukah 6%" [_chan(7)] MSG %"Chanukah 7%" [_chan(8)] MSG %"Chanukah 8%" # Not sure about Reform's position on the next one. IF !Reform # The fast is moved to the 11th if the 10th is a Saturday REM [_PastSat(10, "Tevet")] MSG %"Tzom Tevet%" is %b. ENDIF [_h(15, "Shvat")] ++12 MSG %"Tu B'Shvat%" is %b. [_h(15, "Adar A")] ++12 MSG %"Purim Katan%" is %b. # If Purim is on Sunday, then Fast of Esther is 11 Adar. IF WKDAYNUM(_h2(13, "Adar")) != 6 REM [TRIGGER(_h2(13, "Adar"))] ++12 MSG %"Fast of Esther%" is %b. ELSE REM [TRIGGER(_h2(11, "Adar"))] ++12 MSG %"Fast of Esther%" is %b. ENDIF [_h(14, "Adar")] ++12 MSG %"Purim%" is %b. [_h(15, "Nisan")] ++12 MSG %"Pesach%" is %b. IF !InIsrael [_h(16, "Nisan")] MSG %"Pesach 2%" is %b. ENDIF [_h(21, "Nisan")] MSG %"Pesach 7%" is %b. IF !InIsrael && !Reform [_h(22, "Nisan")] MSG %"Pesach 8%" is %b. ENDIF [_h(27, "Nisan")] ++12 MSG %"Yom HaShoah%" is %b. [_h(4, "Iyar")] ++12 MSG %"Yom HaZikaron%" is %b. [_h(5, "Iyar")] ++12 MSG %"Yom Ha'atzmaut%" is %b. # Not sure about Reform's position on Lag B'Omer IF !Reform [_h(18, "Iyar")] ++12 MSG %"Lag B'Omer%" is %b. ENDIF [_h(28, "Iyar")] ++12 MSG %"Yom Yerushalayim%" is %b. [_h(6, "Sivan")] ++12 MSG %"Shavuot%" is %b. IF !InIsrael && !Reform [_h(7, "Sivan")] MSG %"Shavuot 2%" is %b. ENDIF # Fairly sure Reform Jews don't observe the next two IF !Reform # Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally # fall on a Saturday [_PastSat(17, "Tamuz")] ++12 MSG %"Tzom Tammuz%" is %b. [_PastSat(9, "Av")] ++12 MSG %"Tish'a B'Av%" is %b. ENDIF fset msgprefix(x) "" # Counting the omer - do the whole spiel, i.e: # "This is the xth day of the omer, being y weeks and z days of the omer." # Nice Remind programming example here! SET ostart HEBDATE(16, "Nisan", TODAY()-50) IF ostart <= TODAY() && (TODAY() - ostart < 49) SET odays TODAY()-ostart+1 IF odays < 7 MSG %"%"Today is the [ORD(odays)] day of the Omer. ELSE IF !(odays % 7) MSG %"%"Today is the [ORD(odays)] day of the Omer, being [odays / 7] [PLURAL(odays/7, "week")] of the Omer. ELSE MSG %"%"Today is the [ORD(odays)] day of the Omer, being [odays/7] [PLURAL(odays/7, "week")] and [odays%7] [PLURAL(odays%7, "day")] of the Omer. ENDIF ENDIF CAL [ORD(odays)] of Omer ENDIF IF !$PSCAL REM 20 ++40 msg Also available: a PostScript calendar (about 35KB) for %m %y, complete with Hebrew dates, Jewish holidays, and moon phases for [$Location]. REM 20 ++40 msg And: an HTML version of the above. ELSE [trigger(moondate(0))] SPECIAL MOON 0 [trigger(moondate(1))] SPECIAL MOON 1 [trigger(moondate(2))] SPECIAL MOON 2 [trigger(moondate(3))] SPECIAL MOON 3 REM PS Border Border moveto /DayFont findfont 10 scalefont setfont ([hebday(today())] [hebmon(today())]) show REM SPECIAL HTML

[hebday(today())] [hebmon(today())]

ENDIF remind-03.01.15/www/hebhtml0000644000076400007640000000240312514120343013525 0ustar dfsdfs#!/bin/sh # HTML calendar shell script # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. echo "Content-Type: text/html" echo "" if [ "$1 $2" = " " ] ; then $REMIND - <<'EOR' set thismon monnum(today()) set thisyear year(today()) set nextmon iif(thismon+1 > 12, 1, thismon+1) set nextyear iif(nextmon==1, thisyear+1, thisyear) set lastmon iif(thismon-1 < 1, 12, thismon-1) set lastyear iif(lastmon==12, thisyear-1, thisyear) set nextmon mon(nextmon) set lastmon mon(lastmon) BANNER % REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | $DIR/rem2html --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]" EOR else $REMIND - "$1" "$2" <<'EOR' set thismon monnum(today()) set thisyear year(today()) set nextmon iif(thismon+1 > 12, 1, thismon+1) set nextyear iif(nextmon==1, thisyear+1, thisyear) set lastmon iif(thismon-1 < 1, 12, thismon-1) set lastyear iif(lastmon==12, thisyear-1, thisyear) set nextmon mon(nextmon) set lastmon mon(lastmon) BANNER % REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | $DIR/rem2html --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]" EOR fi exit 0 remind-03.01.15/www/hebps0000644000076400007640000000067012514120343013207 0ustar dfsdfs#!/bin/sh # Hebrew PostScript calendar shell script # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. # Figure out the month: If day <= 20, use this month; otherwise, use # next month. echo "Content-type: application/postscript" echo "" $REMIND - <Ơ^8MꋃIv3S" $REMIND $DIR/moon.rem echo "" exit 0 remind-03.01.15/www/moon.rem-DIST0000644000076400007640000000153312514120343014400 0ustar dfsdfs# File for giving moon phase info. # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. set now now() banner % MSG % MSG Moon over [$Location]% MSG % MSG MSG

Moon over [$Location]

set ndate moondate(0) set ntime moontime(0) set fdate moondate(2) set ftime moontime(2) fset t(x) wkday(x)+", "+day(x)+" "+mon(x)+", "+year(x) msg Today is %w, %d %m, %y.

msg The local time in [$Location] is [now].

if ndate < fdate msg The next new moon is on [t(ndate)] at [ntime], [$Location] time.

msg The next full moon is on [t(fdate)] at [ftime], [$Location] time.

else msg The next full moon is on [t(fdate)] at [ftime], [$Location] time.

msg The next new moon is on [t(ndate)] at [ntime], [$Location] time.

endif remind-03.01.15/www/newmoon.png0000644000076400007640000000055212123136521014353 0ustar dfsdfsPNG  IHDRasBIT|d pHYsftEXtSoftwarewww.inkscape.org<IDAT8*EQFJd$pJx`xLxu@Igvg77D2ەι~kRDhVJ:1n_@D(&8{zv1pT[?uNZPMaѮ񑱂0LʾGյ0ÌKgok)5,ax,v0/. )qOIENDB`remind-03.01.15/www/rem-default.css0000644000076400007640000000204411057403122015077 0ustar dfsdfstable.rem-cal { font-family: helvetica, arial, sans-serif; font-size: 12pt; } table.rem-sc-table { font-family: helvetica, arial, sans-serif; font-size: 10pt; width: 95%; float: left; } caption.rem-cal-caption { font-size: 14pt; font-weight: bold; } th.rem-cal-hdr { width: 14%; border-style: solid; border-width: 1px; vertical-align: top; } td.rem-empty, td.rem-cell, td.rem-small-calendar { width: 14%; height: 7em; border-style: solid; border-width: 1px; vertical-align: top; } td.rem-today { width: 14%; height: 7em; border-style: solid; border-width: 2px; border-color: #EE3333; vertical-align: top; } table.rem-cal { width: 100%; border-collapse: collapse; } div.rem-daynumber { float: right; text-align: right; vertical-align: top; font-size: 14pt; } div.rem-moon { float: left; text-align: left; vertical-align: top; } th.rem-sc-hdr { text-align: right; } td.rem-sc-empty-cell, td.rem-sc-cell { text-align: right; width: 14%; } caption.rem-sc-caption { font-size: 12pt; }remind-03.01.15/www/rem2html0000644000076400007640000003345412514120343013646 0ustar dfsdfs#!/usr/bin/perl use strict; use warnings; use Getopt::Long; my %Options; my $rem2html_version = '2.0'; my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks, @Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen); my $TIDY_PROGNAME = $0; $TIDY_PROGNAME =~ s|^.*/||; # rem2html -- convert the output of "remind -p" to HTML =head1 NAME rem2html - Convert the output of "remind -p" to HTML =head1 SYNOPSIS remind -p ... | rem2html [options] =head1 OPTIONS =over 4 =item --help, -h Print usage information =item --version Print version =item --backurl I When producing the small calendar for the previous month, make the month name a link to I. =item --forwurl I When producing the small calendar for the next month, make the month name a link to I. =item --imgbase I When creating URLs for images and the stylesheet, use I as the base URL. =item --stylesheet I Use I as the stylesheet. If this option is used, I is I interpreted relative to B. =item --nostyle Produce basic HTML that does not use a CSS stylesheet. =item --tableonly Output results as a EtableE ... E/tableE sequence only without any EhtmlE or EbodyE tags. =item --title I Use I<title> as the content between E<lt>titleE<gt> and E<lt>/titleE<gt> tags. =item --prologue I<html_text> Insert I<html_text> right after the E<lt>bodyE<gt> tag. =item --epilogue I<html_text> Insert I<html_text> right before the E<lt>/bodyE<gt> tag. =back =head1 AUTHOR rem2html was written by Dianne Skoll with much inspiration from an earlier version by Don Schwarz. =cut sub usage { my ($exit_status) = @_; if (!defined($exit_status)) { $exit_status = 1; } print STDERR <<"EOM"; $TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -p" Usage: remind -p ... | rem2html [options] Options: --help, -h Print usage information --man Show man page (requires "perldoc") --version Print version --backurl url Make the title on the previous month's small calendar entry a link to <url> --forwurl url Same as --backurl, but for the next month's small calendar --imgbase url Base URL of images and default stylesheet file --stylesheet url.css URL of CSS stylesheet. If specified, imgbase is NOT prepended to url.css --nostyle Produce basic HTML that does not use a CSS stylesheet --tableonly Output results as a <table> only, no <html>, <body>, etc. --title string What to put in <title>... tags --prologue html_text Text to insert at the top of the body --epilogue html_text Text to insert at the end of the body EOM exit($exit_status); } sub parse_options { local $SIG{__WARN__} = sub { print STDERR "$TIDY_PROGNAME: $_[0]\n"; }; if (!GetOptions(\%Options, "help|h", "man", "version", "stylesheet=s", "nostyle", "backurl=s", "forwurl=s", "title=s", "prologue=s", "epilogue=s", "imgbase=s", "tableonly")) { usage(1); } $Options{'title'} ||= 'HTML Calendar'; # Fix up imgbase my $imgbase = '%IMAGEBASE%'; if ($imgbase ne '%' . 'IMAGEBASE' . '%') { $Options{'imgbase'} ||= $imgbase; } else { $Options{'imgbase'} ||= ''; } $Options{'imgbase'} =~ s|/+$||; my $stylesheet = $Options{'imgbase'}; $stylesheet .= '/' if ($stylesheet ne ''); $stylesheet .= 'rem-default.css'; $Options{'stylesheet'} ||= $stylesheet; } sub start_output { return if ($Options{'tableonly'}); print("\n\n" . $Options{'title'} . "\n"); if (!$Options{'nostyle'}) { if ($Options{'stylesheet'}) { print('' . "\n"); } } print("\n\n"); if ($Options{'prologue'}) { print $Options{'prologue'} . "\n"; } } sub end_output { return if ($Options{'tableonly'}); if ($Options{'epilogue'}) { print $Options{'epilogue'} . "\n"; } print("\n\n"); } sub parse_input { undef $days; undef $shades; undef $moons; undef $classes; undef $weeks; my $found_data = 0; while() { chomp; last if /^\# rem2ps begin$/; } my $line; # Month Year numdays firstday monday_first_flag $line = ; return 0 unless $line; chomp($line); ($Month, $Year, $Numdays, $Firstwkday, $Mondayfirst) = split(' ', $line); # Day names $line = ; return 0 unless $line; chomp($line); @Daynames = split(' ', $line); # Prevmon prevlen $line = ; return 0 unless $line; chomp($line); ($Prevmon, $Prevlen) = split(' ', $line); # Nextmon nextlen $line = ; return 0 unless $line; chomp($line); ($Nextmon, $Nextlen) = split(' ', $line); $found_data = 1; my $class; if ($Options{'nostyle'}) { $class = ''; } else { $class = ' class="rem-entry"'; } while() { chomp; last if /^\# rem2ps end$/; next if /^\#/; next unless m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/; my ($y, $m, $d, $special, $tag, $duration, $time, $body) = ($1, $2, $3, $4, $5, $6, $7, $8); my $d1 = $d; $d1 =~ s/^0+//; if ($special eq 'HTML') { push(@{$days->[$d]}, $body); } elsif ($special eq 'HTMLCLASS') { $classes->[$d] = $body; } elsif ($special eq 'WEEK') { $body =~ s/^\s+//; $body =~ s/\s+$//; $weeks->{$d1} = $body; } elsif ($special eq 'MOON') { if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) { my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4); $moons->[$d]->{'phase'} = $phase; $moons->[$d]->{'msg'} = $msg; } elsif ($body =~ /(\S+)/) { $moons->[$d]->{'phase'} = $1; $moons->[$d]->{'msg'} = ''; } } elsif ($special eq 'SHADE') { if ($body =~ /(\d+)\s+(\d+)\s+(\d+)/) { $shades->[$d] = sprintf("#%02X%02X%02X", ($1 % 256), ($2 % 256), ($3 % 256)); } } elsif ($special eq 'COLOR' || $special eq 'COLOUR') { if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/) { my($r, $g, $b, $text) = ($1, $2, $3, $4); my $color = sprintf("style=\"color: #%02X%02X%02X;\"", $r % 256, $g % 256, $b % 256); push(@{$days->[$d]}, "" . escape_html($text) . '

'); } } elsif ($special eq '*') { push(@{$days->[$d]}, "" . escape_html($body) . '

'); } } return $found_data; } sub small_calendar { my($month, $monlen, $url, $first_col) = @_; if ($Mondayfirst) { $first_col--; if ($first_col < 0) { $first_col = 6; } } if ($Options{'nostyle'}) { print "\n"; print "\n"; print "\n"; } sub output_calendar { # Which column is 1st of month in? my $first_col = $Firstwkday; if ($Mondayfirst) { $first_col--; if ($first_col < 0) { $first_col = 6; } } # Last column my $last_col = ($first_col + $Numdays - 1) % 7; # Start the table my $class; if ($Options{'nostyle'}) { print '
"; } else { print "
\n"; print "\n"; print "\n"; my $class; if ($Options{'nostyle'}) { print ''; $class = ' align="right"'; } else { print ''; $class = ' class="rem-sc-hdr"'; } if (!$Mondayfirst) { print "" . substr($Daynames[0], 0, 1) . ''; } for (my $i=1; $i<7; $i++) { print "" . substr($Daynames[$i], 0, 1) . ''; } if ($Mondayfirst) { print "" . substr($Daynames[0], 0, 1) . ''; } print("\n"); my $col = 0; for (; $col<$first_col; $col++) { if ($col == 0) { print("\n"); } if ($Options{'nostyle'}) { print(""); } else { print(""); } } for (my $day=1; $day <= $monlen; $day++) { if ($col == 0) { print("\n"); } $col++; if ($Options{'nostyle'}) { print(""); } else { print(""); } if ($col == 7) { print("\n"); $col = 0; } } if ($col) { while ($col < 7) { if ($Options{'nostyle'}) { print(""); } else { print(""); } $col++; } print("\n"); } print("
"; } print "" if ($url); print $month; print "" if ($url); print "
  
$day$day
  
\n"); print "
' . "\n"; print ''; $class = ' width="14%"'; } else { print '
' . $Month . ' ' . $Year . '
' . "\n"; print ''; $class = ' class="rem-cal-hdr"'; } if (!$Mondayfirst) { print "" . $Daynames[0] . ''; } for (my $i=1; $i<7; $i++) { print "" . $Daynames[$i] . ''; } if ($Mondayfirst) { print "" . $Daynames[0] . ''; } print "\n"; # Start the calendar rows my $col = 0; if ($Options{'nostyle'}) { print "\n"; } else { print "\n"; } if ($first_col > 0) { small_calendar($Prevmon, $Prevlen, $Options{'backurl'}, ($Firstwkday - $Prevlen + 35) % 7); $col++; } if ($last_col == 6 && $first_col > 0) { small_calendar($Nextmon, $Nextlen, $Options{'forwurl'}, ($Firstwkday + $Numdays) % 7); $col++; } if ($Options{'nostyle'}) { $class = ' width="14%"'; } else { $class = ' class="rem-empty"'; } while ($col < $first_col) { print(" \n"); $col++; } for (my $day=1; $day<=$Numdays; $day++) { draw_day_cell($day); $col++; if ($col == 7) { $col = 0; print "\n"; if ($day < $Numdays) { if ($Options{'nostyle'}) { print "\n"; } else { print "\n"; } } } } if ($col) { while ($col < 7) { if ($col == 5) { if ($first_col == 0) { small_calendar($Prevmon, $Prevlen, $Options{'backurl'}, ($Firstwkday - $Prevlen + 35) % 7); } else { print(" \n"); } } elsif ($col == 6) { small_calendar($Nextmon, $Nextlen, $Options{'forwurl'}, ($Firstwkday + $Numdays) % 7); } else { print(" \n"); } $col++; } print "\n"; } # Add a row for small calendars if they were not yet done! if ($first_col == 0 && $last_col == 6) { if ($Options{'nostyle'}) { print "\n"; } else { print "\n"; } small_calendar($Prevmon, $Prevlen, $Options{'backurl'}, ($Firstwkday - $Prevlen + 35) % 7); for (my $i=0; $i<5; $i++) { print(" \n"); } small_calendar($Nextmon, $Nextlen, $Options{'forwurl'}, ($Firstwkday + $Numdays) % 7); print("\n"); } # End the table print "
' . $Month . ' ' . $Year . '
\n"; } sub draw_day_cell { my($day) = @_; my $shade = $shades->[$day]; my $week = ''; if (exists($weeks->{$day})) { $week = ' ' . $weeks->{$day}; } my $class; if ($Options{'nostyle'}) { $class = $classes->[$day] || ''; } else { $class = $classes->[$day] || "rem-cell"; } if ($shade) { $shade = " style=\"background: $shade;\""; } else { $shade = ""; } if ($class ne '') { print "\n"; } else { print "\n"; } if ($moons->[$day]) { my $phase = $moons->[$day]->{'phase'}; my $msg = $moons->[$day]->{'msg'}; $msg ||= ''; if ($msg ne '') { $msg = ' ' . escape_html($msg); } my $img; my $alt; my $title; if ($phase == 0) { $img = 'newmoon.png'; $title = 'New Moon'; $alt = 'new'; } elsif ($phase == 1) { $img = 'firstquarter.png'; $title = 'First Quarter'; $alt = '1st'; } elsif ($phase == 2) { $img = 'fullmoon.png'; $alt = 'full'; $title = 'Full Moon'; } else { $img = 'lastquarter.png'; $alt = 'last'; $title = 'Last Quarter'; } if ($Options{'imgbase'}) { $img = $Options{'imgbase'} . '/' . $img; } if ($Options{'nostyle'}) { print("
\"$alt\"$msg
"); } else { print("
\"$alt\"$msg
"); } } if ($Options{'nostyle'}) { print "
$day$week
\n"; print "

 

\n"; } else { print "
$day$week
\n"; } if ($days->[$day]) { print(join("\n", @{$days->[$day]})); } print "\n"; } sub escape_html { my($in) = @_; $in =~ s/\&/\&/g; $in =~ s/\/\>/g; return $in; } parse_options(); if ($Options{'help'}) { usage(0); exit(0); } elsif ($Options{'man'}) { system("perldoc $0"); exit(0); } elsif ($Options{'version'}) { print "rem2html version $rem2html_version.\n"; exit(0); } if (-t STDIN) { print STDERR "$TIDY_PROGNAME: Input should not come from a terminal.\n\n"; usage(1); } my $found_something = 0; while(1) { last if (!parse_input()); start_output() unless $found_something; $found_something = 1; output_calendar(); } if ($found_something) { end_output(); exit(0); } else { print STDERR "$TIDY_PROGNAME: Could not find any calendar data on STDIN.\n"; exit(1); } remind-03.01.15/www/sunrise0000644000076400007640000000041612514120343013574 0ustar dfsdfs#!/bin/sh # Sunrise shell script # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. echo Content-type: text/html echo echo "" $REMIND -arqh $DIR/sunrise.rem echo "" exit 0 remind-03.01.15/www/sunrise.rem-DIST0000644000076400007640000000242512514120343015121 0ustar dfsdfs# File for giving sunrise info # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. set now now() banner % MSG % MSG Sunrise in [$Location]% MSG % MSG MSG

Sunrise in [$Location]

set tod sunrise(today()) set tom sunrise(today()+1) set len1 sunset(today())-sunrise(today()) set len2 sunset(today()+1)-sunrise(today()+1) set dlen len2-len1 set slen iif(dlen==0, "the same length as", dlen<0, abs(dlen)+plural(abs(dlen)," minute", " minutes")+" shorter than", dlen+plural(dlen, " minute", " minutes")+" longer than") set diff tod-now set adiff abs(diff) set hdiff adiff/60 set mdiff adiff%60 set mstr iif(mdiff==0, "", mdiff == 1, "1 minute", mdiff + " minutes") set hstr iif(hdiff==0, "", hdiff == 1, "1 hour", hdiff + " hours") set astr iif(mdiff!=0 && hdiff!=0, " and ", "") set fn iif(diff==0, "now", diff <0, "ago", "from now") set iw iif(diff<0, "was", "is") set aw iif(tod==tom, " as well.", ".") msg Today is %w, %d %m, %y.

msg The local time in [$Location] is [now].

msg Sunrise today [iw] at [tod]; in other words, [hstr][astr][mstr] [fn].

msg Sunrise tomorrow is at [tom][aw]

msg The daylight portion of tomorrow will be [slen] today.

msg remind-03.01.15/www/sunset0000644000076400007640000000041412514120343013423 0ustar dfsdfs#!/bin/sh # Sunset shell script # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. echo Content-type: text/html echo echo "" $REMIND -arqh $DIR/sunset.rem echo "" exit 0 remind-03.01.15/www/sunset.rem-DIST0000644000076400007640000000241712514120343014753 0ustar dfsdfs# File for giving sunset info # # This file is part of REMIND. # Copyright (C) 1992-1997 by Dianne Skoll # Copyright (C) 1999-2000 by Roaring Penguin Software Inc. set now now() banner % MSG % MSG Sunset in [$Location]% MSG % MSG MSG

Sunset in [$Location]

set tod sunset(today()) set tom sunset(today()+1) set len1 sunset(today())-sunrise(today()) set len2 sunset(today()+1)-sunrise(today()+1) set dlen len2-len1 set slen iif(dlen==0, "the same length as", dlen<0, abs(dlen)+plural(abs(dlen)," minute", " minutes")+" shorter than", dlen+plural(dlen, " minute", " minutes")+" longer than") set diff tod-now set adiff abs(diff) set hdiff adiff/60 set mdiff adiff%60 set mstr iif(mdiff==0, "", mdiff == 1, "1 minute", mdiff + " minutes") set hstr iif(hdiff==0, "", hdiff == 1, "1 hour", hdiff + " hours") set astr iif(mdiff!=0 && hdiff!=0, " and ", "") set fn iif(diff==0, "now", diff <0, "ago", "from now") set iw iif(diff<0, "was", "is") set aw iif(tod==tom, " as well.", ".") msg Today is %w, %d %m, %y.

msg The local time in [$Location] is [now].

msg Sunset today [iw] at [tod]; in other words, [hstr][astr][mstr] [fn].

msg Sunset tomorrow is at [tom][aw]

msg The daylight portion of tomorrow will be [slen] today.

msg