mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 14:28:40 +02:00
Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb1998c888 | ||
|
|
543252cbaf | ||
|
|
6df7c59876 | ||
|
|
f780e0afc3 | ||
|
|
310e8d3287 | ||
|
|
ba51bdf258 | ||
|
|
ef88b844fb | ||
|
|
67b96b0a26 | ||
|
|
562da30fb5 | ||
|
|
21175e8cf6 | ||
|
|
80d01f7158 | ||
|
|
90cac447e4 | ||
|
|
04bf5b0a8b | ||
|
|
d667c15b25 | ||
|
|
2123bf4b18 | ||
|
|
429a64f29e | ||
|
|
f39381dd6c | ||
|
|
0a9eb07f6f | ||
|
|
9c287e3fd7 | ||
|
|
cce4b2cb14 | ||
|
|
e49d9f8ab6 | ||
|
|
48cbeb28f4 | ||
|
|
57d5c54559 | ||
|
|
3b2260f67e | ||
|
|
d423a62327 | ||
|
|
ac8da00030 | ||
|
|
77eb7fb99d | ||
|
|
a751149dd3 | ||
|
|
69d45618c6 | ||
|
|
22fa1a28e5 | ||
|
|
f4cc233009 | ||
|
|
1d6e4edd0f | ||
|
|
daffa8cba0 | ||
|
|
2e161a1bc1 | ||
|
|
204bb00060 | ||
|
|
d6029a54aa | ||
|
|
f99b5c5a66 | ||
|
|
2df4119c1a | ||
|
|
d06b4e5dcd | ||
|
|
bf8a25137d | ||
|
|
0f302ad0fc | ||
|
|
e3d6b283c5 | ||
|
|
2e3ed09039 | ||
|
|
37971a3f07 | ||
|
|
2a1960f257 | ||
|
|
350564c304 | ||
|
|
9e2a9fea37 | ||
|
|
3592b43629 | ||
|
|
becf1fc459 | ||
|
|
2bccd058ed | ||
|
|
12c6621051 | ||
|
|
504bc6a875 | ||
|
|
9cfdd0b53f | ||
|
|
d59024f399 | ||
|
|
24e0178d1a | ||
|
|
1ede5775f2 | ||
|
|
a5c9b07052 | ||
|
|
22353d4833 | ||
|
|
7499ada891 | ||
|
|
3f0a4e5c39 | ||
|
|
b8d6472974 | ||
|
|
6358297724 | ||
|
|
4f6dcde980 | ||
|
|
8a7985c48e | ||
|
|
4ddbe54e55 | ||
|
|
ef0bf73a29 | ||
|
|
beda9014d8 | ||
|
|
498a429b2c | ||
|
|
6aa2aa0fb3 | ||
|
|
1bef88fccd | ||
|
|
8308068067 | ||
|
|
8385c7f1b0 | ||
|
|
0537d02fef | ||
|
|
c33a1a3b0b | ||
|
|
fd39999128 | ||
|
|
0aa40094fa | ||
|
|
e3bbbe07be | ||
|
|
5633798d33 | ||
|
|
0e7e1b1b75 | ||
|
|
4d3790bc1a | ||
|
|
2002c7f1f8 | ||
|
|
1be14e99a2 | ||
|
|
78efdaf85f | ||
|
|
0e98a1c656 | ||
|
|
7aa483e201 | ||
|
|
a6dbf05af4 | ||
|
|
8ab78fd8be | ||
|
|
4f119031a4 | ||
|
|
19bdd6c2db | ||
|
|
f1557b8243 | ||
|
|
85f96e2e01 | ||
|
|
47331cd919 | ||
|
|
d9f18ed6a7 | ||
|
|
efa4816371 | ||
|
|
2dc8c63adb | ||
|
|
c3c1781021 | ||
|
|
cd39480a98 | ||
|
|
281a1a206e | ||
|
|
cbff2a7bf2 | ||
|
|
2a08be8fd0 | ||
|
|
0826678209 | ||
|
|
f2e421bfa5 | ||
|
|
ce53a9b91a | ||
|
|
b166b1cf82 | ||
|
|
d09fbb03b2 | ||
|
|
7a835f3b10 | ||
|
|
6b991cdf9c | ||
|
|
018e9d0323 | ||
|
|
f499ae096f | ||
|
|
725e046a15 | ||
|
|
275b1f62b6 | ||
|
|
6e58dea198 | ||
|
|
ad4e62c8c3 | ||
|
|
a5768d55d8 | ||
|
|
7db49971c8 | ||
|
|
45ca6631ac | ||
|
|
d51944f36c | ||
|
|
037c79fb0f | ||
|
|
993373414f | ||
|
|
38a0a9992a | ||
|
|
a82bbe3776 | ||
|
|
a32ba217ba | ||
|
|
d322cf54ac | ||
|
|
b1d07a231d | ||
|
|
97851a08e6 | ||
|
|
8547b30a8f |
@@ -3,7 +3,7 @@ THE REMIND COPYRIGHT
|
||||
1. REMIND refers to the entire set of files and documentation in the
|
||||
REMIND package.
|
||||
|
||||
2. REMIND is Copyright 1992-2018 Dianne Skoll, except where noted in
|
||||
2. REMIND is Copyright 1992-2020 Dianne Skoll, except where noted in
|
||||
individual files.
|
||||
|
||||
3. DISTRIBUTION AND USE
|
||||
|
||||
2
configure
vendored
2
configure
vendored
@@ -3991,7 +3991,7 @@ _ACEOF
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION=03.03.00
|
||||
VERSION=03.03.06
|
||||
|
||||
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"
|
||||
|
||||
|
||||
@@ -75,6 +75,6 @@ if test "$GCC" = yes; then
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
|
||||
VERSION=03.03.00
|
||||
VERSION=03.03.06
|
||||
AC_SUBST(VERSION)
|
||||
AC_OUTPUT(src/Makefile www/Makefile src/version.h)
|
||||
|
||||
110
docs/WHATSNEW
110
docs/WHATSNEW
@@ -1,5 +1,115 @@
|
||||
CHANGES TO REMIND
|
||||
|
||||
* VERSION 3.3 Patch 6 - 2021-03-30
|
||||
|
||||
- test/test.rem: Change local to en_US.utf-8 only if current locale
|
||||
is not a UTF-8 locale.
|
||||
|
||||
- MINOR CHANGE: Remind's arithemtic operators (+, -, *, /) give errors
|
||||
on overflow rather than silently giving the wrong answer.
|
||||
|
||||
- MINOR CHANGE: Add $IntMin and $IntMax system variables.
|
||||
|
||||
- DOCUMENTATION FIX: Document that TkRemind now requires Tcl/Tk version
|
||||
8.5 or newer.
|
||||
|
||||
* VERSION 3.3 Patch 5 - 2021-01-21
|
||||
|
||||
- NEW FEATURE: tkremind: Add ability to change fonts and colors from
|
||||
within TkRemind "Options" dialog.
|
||||
|
||||
- CHANGE: tkremind: TkRemind now requires Tcl/Tk 8.5 or newer.
|
||||
|
||||
- CHANGE: tkremind: You can specify the location of the options
|
||||
file on the command-line if you want to use one other than ~/.tkremindrc
|
||||
|
||||
- CLEANUP: tkremind: Remove "Apply Options" from Options dialog; we only
|
||||
need "Save Options".
|
||||
|
||||
- DOC FIX: Add missing release note in 3.3.4 notes regarding
|
||||
setpagedevice patch
|
||||
|
||||
- DOC FIX: tkremind: Document shortcut keys.
|
||||
|
||||
* VERSION 3.3 Patch 4 - 2021-01-12
|
||||
|
||||
- NEW FEATURE: If "inotifywait" is installed, TkRemind uses it to refresh
|
||||
the calendar display right away when the reminders file/directory is updated.
|
||||
This makes TkRemind react almost instantly if external tools are editing
|
||||
or updating reminders.
|
||||
|
||||
- MINOR NEW FEATURE: rem2ps has a new '-x' option; this puts the day numbers
|
||||
on the top-left of the day's box instead of the top-right.
|
||||
|
||||
- MINOR FIXES: A typo in remind.1 was fixed; additional comments regarding
|
||||
UNTIL were added.
|
||||
|
||||
- BUG FIX: rem2ps: Call setpagedevice to set page size. Based on a patch
|
||||
from Jonathan Kamens.
|
||||
|
||||
* VERSION 3.3 Patch 3 - 2020-11-09
|
||||
|
||||
- BUG FIX: Fix startup crash in TkRemind if "Show Today's Reminders on
|
||||
Startup" is enabled (which, unfortunately, is the default.) Bug reported
|
||||
by Martin Ziemer.
|
||||
|
||||
* VERSION 3.3 Patch 2 - 2020-11-08
|
||||
|
||||
- MINOR NEW FEATURE: Add MAYBE-UNCOMPUTABLE keyword; see the man page
|
||||
and discussion at
|
||||
https://dianne.skoll.ca/pipermail/remind-fans/2020/003745.html
|
||||
|
||||
- CHANGE: TkRemind always invokes Remind with the "-itkremind=1" option,
|
||||
even when printing. NOTE INCOMPATIBILITY: This is a behavior change!
|
||||
When you print from TkRemind, we also invoke Remind with "-itkprint=1"
|
||||
so you can detect that PostScript is being generated.
|
||||
|
||||
- CHANGE: The maxmimum length of a variable name has been increased from
|
||||
16 characters to 64 characters. Modern computers have plenty of memory.
|
||||
|
||||
- BUG FIXES: Minor documentation updates, typo fixes, clarifications, etc.
|
||||
|
||||
- BUG FIX: Fix calendar-drawing alignment errors when displaying UTF-8
|
||||
strings with zero-width combining characters and strings with tabs.
|
||||
|
||||
- BUG FIX: TkRemind would mess up placement of the WEEK special if invoked
|
||||
with the "-m" option. This has been fixed.
|
||||
|
||||
- BUG FIX: TkRemind would sometimes fail with an error message when editing
|
||||
a reminder; this is because it was interpreting months 08 and 09 as
|
||||
illegal octal numbers. This has been fixed.
|
||||
|
||||
* VERSION 3.3 Patch 1 - 2020-03-20
|
||||
|
||||
- CHANGE: For overlapping multi-day events, issue a reminder for the
|
||||
most *recent* event rather than the earliest event. NOTE
|
||||
INCOMPATIBILITY: This is a behavior change!
|
||||
|
||||
- CHANGE: Do not convert 90-99 to 1990-1999 when parsing numbers to
|
||||
recognize years. NOTE INCOMPATIBILITY: This is a behavior change!
|
||||
|
||||
- CHANGE: Revert change to -y option that included filename and line
|
||||
number in the hash.
|
||||
|
||||
- CHANGE: Retain newlines (produced by %_) in JSON output.
|
||||
|
||||
- FIX: Document $FormWidth system variable
|
||||
|
||||
- FIX: Highlight today's date in "remind -c" output
|
||||
|
||||
- FIX: Eliminate compiler warnings on Ubuntu 18.04.
|
||||
|
||||
- IMPROVEMENT: Allow times to be specified either in 24-hour mode
|
||||
(HH:MM or HH.MM) or AM/PM mode (HH:MMam; HH:MMpm, etc.)
|
||||
|
||||
- IMPROVEMENT: Allow DURATION to be specified as a time (1:30) or a
|
||||
number of minutes (90).
|
||||
|
||||
- IMPROVEMENT: If terminal size can be determined, set $FormWidth to
|
||||
terminal width - 8; if not, set $FormWidth to 72.
|
||||
|
||||
- MINOR IMPROVEMENT: Add the "ampm()" built-in function.
|
||||
|
||||
* Version 3.3 Patch 0 - 2020-01-31
|
||||
|
||||
- FIX: rem2ps: Add a %%PageBoundingBox: document structuring convention
|
||||
|
||||
@@ -26,8 +26,8 @@ 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.%
|
||||
IF version() < "03.01.09"
|
||||
ERRMSG This file requires at least version 03.01.09 of Remind.%
|
||||
ERRMSG This version is version [version()].
|
||||
EXIT
|
||||
ENDIF
|
||||
@@ -84,7 +84,6 @@ SET December 12
|
||||
###########################################################
|
||||
# Other symbolic constants and functions for "pasting"... #
|
||||
###########################################################
|
||||
|
||||
SET Quote CHAR(34)
|
||||
|
||||
# Handy constants/function for specifing week of month...
|
||||
@@ -95,29 +94,17 @@ 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")
|
||||
FSET _back(days) $U-days
|
||||
|
||||
#################################################################
|
||||
# Function which removes a single leading zero from a string... #
|
||||
# Function that 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)
|
||||
|
||||
@@ -125,26 +112,12 @@ 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)
|
||||
FSET _yr_num(yr) ORD($Ty - yr)
|
||||
FSET _mo_num(mo, yr) ORD(12 * ($Ty - yr) + $Tm - 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")
|
||||
REM 1 Nov ++12 MSG %"John's [_yr_num(1984)] birthday%" is %b.
|
||||
REM 1 MSG John's [_mo_num(11, 1984)] 'monthly' anniversary
|
||||
|
||||
#############################################################################
|
||||
# Here's a tricky problem: The 4th of July is a holiday in the U.S.
|
||||
@@ -158,29 +131,28 @@ FSET _mail(from, subj) "fastmail -f " + \
|
||||
# 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.
|
||||
# The SCANFROM clause will make these OMITs 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)
|
||||
SET iday $T
|
||||
IF WKDAYNUM(iday) == Sat
|
||||
REM [iday] MSG Independence day (actual)
|
||||
OMIT [iday-1] MSG Independence day (observed)
|
||||
ELSE
|
||||
IF WKDAYNUM(TRIGDATE()) == Sun
|
||||
REM [TRIGDATE()] MSG Independence day (actual)
|
||||
OMIT [TRIGDATE()+1] MSG Independence day (observed)
|
||||
IF WKDAYNUM(iday) == Sun
|
||||
REM [iday] MSG Independence day (actual)
|
||||
OMIT [iday+1] MSG Independence day (observed)
|
||||
ELSE
|
||||
OMIT [TRIGDATE()] MSG Independence day
|
||||
OMIT [iday] 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
|
||||
@@ -192,68 +164,21 @@ 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
|
||||
IF ISOMITTED($T-7)
|
||||
REM [$T] 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 #
|
||||
# On our UNIX system, I run a program that 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. #
|
||||
# than today(). #
|
||||
# #
|
||||
##########################################################################
|
||||
|
||||
IF !$RunOff && !$CalMode && !$SimpleCal
|
||||
IF REALTODAY()-FILEDATE("/home/dfs/.booksdue") >= 7
|
||||
REM RUN /home/dfs/bilge/library/getbooks
|
||||
@@ -283,7 +208,7 @@ REM Sat Sun SPECIAL SHADE 220
|
||||
#############################################################################
|
||||
|
||||
SET SaveTrig $NumTrig
|
||||
SET easter EASTERDATE(YEAR(TODAY()))
|
||||
SET easter EASTERDATE($Uy)
|
||||
REM [easter-46] MSG %"Ash Wednesday%"
|
||||
REM [easter-7] MSG %"Palm Sunday%"
|
||||
OMIT [easter-2] MSG %"Good Friday%"
|
||||
@@ -301,7 +226,7 @@ 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%"
|
||||
OMIT [$T] MSG %"President's Day%"
|
||||
REM Mar 17 MSG %"St. Patrick's%" Day
|
||||
|
||||
# The DST rules are accurate for most locations in
|
||||
@@ -319,23 +244,23 @@ 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%"
|
||||
OMIT [$T] 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%"
|
||||
OMIT [$T] MSG %"Labor Day%"
|
||||
REM Mon Oct [Week_2] MSG %"Columbus Day%"
|
||||
REM Nov 11 MSG %"Veterans Day%"
|
||||
|
||||
REM Oct 30 MSG %"Mischief Night%"
|
||||
REM Oct 31 MSG %"Halloween%"
|
||||
REM Tue Nov 2 SCANFROM [_back(7)] \
|
||||
SATISFY [(YEAR(TRIGDATE()) % 4) == 0] \
|
||||
SATISFY [($Ty % 4) == 0] \
|
||||
MSG %"Election%" Day
|
||||
REM Thu Nov [Week_4] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Thanksgiving%" Day
|
||||
OMIT [$T] MSG %"Thanksgiving%" Day
|
||||
REM Fri Nov [Week_4+1] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Thanksgiving%" (cont.)
|
||||
OMIT [$T] MSG %"Thanksgiving%" (cont.)
|
||||
OMIT Dec 24 MSG %"Christmas Eve%"
|
||||
OMIT Dec 25 MSG %"Christmas%" Day
|
||||
|
||||
@@ -350,13 +275,6 @@ 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
|
||||
##########################################################################
|
||||
# #
|
||||
@@ -370,7 +288,7 @@ REM Dec [IIF((YEAR(TODAY())+1)%4, 21, 22)] MSG %"Winter%" begins
|
||||
# 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
|
||||
([hebday($U)] [hebmon($U)]) show
|
||||
|
||||
# Fill in the phases of the moon on the PostScript calendar
|
||||
[moondate(0)] SPECIAL MOON 0
|
||||
@@ -382,7 +300,7 @@ REM PS Border Border moveto \
|
||||
# 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
|
||||
(Sunrise: [sunrise($T)] Sunset: [sunset($T)]) 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
|
||||
@@ -390,7 +308,7 @@ REM PS Border Border 5 sub moveto \
|
||||
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
|
||||
([_DayOfYear($U)]([365+isleap($U)-_DayOfYear($U)])) show
|
||||
|
||||
#JHOLS
|
||||
##########################################################################
|
||||
@@ -430,7 +348,7 @@ 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 _h2(x, y) HEBDATE(x, y, $U-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)
|
||||
@@ -464,7 +382,7 @@ ELSE
|
||||
ENDIF
|
||||
|
||||
# Because Kislev can change length, we must be more careful about Chanukah
|
||||
FSET _chan(x) HEBDATE(24, "Kislev", today()-9)+x
|
||||
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
||||
[_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
|
||||
[_chan(2)] MSG %"Chanukah 2%"
|
||||
[_chan(3)] MSG %"Chanukah 3%"
|
||||
@@ -553,9 +471,9 @@ 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
|
||||
SET ostart HEBDATE(16, "Nisan", $U-50)
|
||||
IF ostart <= $U && ($U - ostart < 49)
|
||||
SET odays $U-ostart+1
|
||||
IF odays < 7
|
||||
MSG %"%"Today is the [ORD(odays)] day of the Omer.
|
||||
ELSE
|
||||
@@ -573,8 +491,8 @@ ENDIF
|
||||
### 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]
|
||||
REM Friday CAL Candle lighting at [sunset($T)-18]
|
||||
REM Saturday CAL Havdalah at [sunset($T)+42]
|
||||
|
||||
#COLORS
|
||||
##########################################################################
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH REM2PS 1 "1 January 2020"
|
||||
.TH REM2PS 1 "5 January 2021"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
rem2ps \- draw a PostScript calendar from Remind output
|
||||
@@ -29,6 +29,11 @@ include any document structuring comments in your prologue.
|
||||
Produce the calendar in landscape mode rather than the default
|
||||
portrait mode.
|
||||
.TP
|
||||
.B \-x
|
||||
When printing the calendar, place the day numbers in the top-left of each
|
||||
day's box. If this option is omitted, the day numbers appear in the
|
||||
top-right.
|
||||
.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
|
||||
|
||||
201
man/remind.1
201
man/remind.1
@@ -26,7 +26,7 @@ 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".
|
||||
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
|
||||
@@ -248,7 +248,7 @@ 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.
|
||||
the section "SORTING REMINDERS" for more information.
|
||||
|
||||
.TP
|
||||
\fB\-b\fR[\fIn\fR]
|
||||
@@ -323,7 +323,7 @@ TAG clause.
|
||||
\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.
|
||||
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.
|
||||
@@ -334,14 +334,15 @@ If you supply a \fIdate\fR on the command line, it must consist of
|
||||
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.
|
||||
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 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. The \fItime\fR may be specified in 24-hour format (eg, 13:20)
|
||||
or common "AM/PM" format (1:20pm).
|
||||
.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
|
||||
@@ -351,7 +352,7 @@ 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
|
||||
"Repeated Execution" in the section "CALENDAR MODE" for more
|
||||
information.
|
||||
.SH REMINDER FILES
|
||||
.PP
|
||||
@@ -438,7 +439,7 @@ 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
|
||||
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.
|
||||
@@ -456,7 +457,7 @@ 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."
|
||||
\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
|
||||
@@ -517,7 +518,7 @@ characters must be used. The following are examples of the various parts of a
|
||||
JANUARY, feb, March, ApR, may, Aug
|
||||
.TP
|
||||
.I year:
|
||||
1990, 1993, 2030, 95 (interpreted as 1995). The year can range
|
||||
1990, 1993, 2030. The year can range
|
||||
from 1990 to 2075.
|
||||
.TP
|
||||
.I weekday:
|
||||
@@ -814,7 +815,7 @@ the initial date, and does not affect the repetition period.
|
||||
.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"
|
||||
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.
|
||||
@@ -826,7 +827,7 @@ 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
|
||||
\fB$DefaultPrio\fR. See the section "SYSTEM VARIABLES" for more
|
||||
information.)
|
||||
.PP
|
||||
.B EXPIRY DATES
|
||||
@@ -859,6 +860,20 @@ As a special case, you can use the \fBTHROUGH\fR keyword instead of
|
||||
REM 1992-11-30 +2 THROUGH 1992-12-04 MSG Jury duty
|
||||
.fi
|
||||
.PP
|
||||
If you have an expiry date via the use of \fBTHROUGH\fR or \fBUNTIL\fR,
|
||||
then Remind will \fInever\fR trigger the reminder after the expiry
|
||||
date. For example, if you have this:
|
||||
.PP
|
||||
.nf
|
||||
OMIT 2021-01-08
|
||||
REM 2021-01-01 THROUGH 2021-01-08 AFTER MSG Test
|
||||
.fi
|
||||
.PP
|
||||
the reminder will not be triggered on 2021-01-08, and nor will it be
|
||||
triggered on 2021-01-09; even though the AFTER keyword would normally
|
||||
move the 8th's reminder to the 9th, the expiry date of 2021-01-08
|
||||
overrides that.
|
||||
.PP
|
||||
.B THE ONCE KEYWORD
|
||||
.PP
|
||||
Sometimes, it is necessary to ensure that reminders are run only once
|
||||
@@ -967,8 +982,13 @@ it terminates the search after the \fBSATISFY\fR iteration limit
|
||||
.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,
|
||||
may be specified in 24-hour format, with 0:00 representing midnight,
|
||||
12:00 representing noon, and 23:59 representing one minute to midnight.
|
||||
Alternatively, it may be specified in common "AM/PM" format; in this case,
|
||||
the hour must range from 1 to 12. 12:00am represents midnight, 12:00pm
|
||||
represents noon, and 11:59pm represents one minute to midnight. The "am"
|
||||
and "pm" portions are case-insensitive and the "m" is optional.
|
||||
.PP
|
||||
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
|
||||
@@ -995,7 +1015,7 @@ 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.
|
||||
REM Fri ++1 AT 1:00PM MSG Lunch at 1pm Friday.
|
||||
.fi
|
||||
.PP
|
||||
The \fItdelta\fR and \fItrepeat\fR have the same form as a \fIrepeat\fR
|
||||
@@ -1055,7 +1075,7 @@ 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.
|
||||
"PRECISE SCHEDULING" further on.
|
||||
.PP
|
||||
.B TAG AND DURATION
|
||||
.PP
|
||||
@@ -1077,15 +1097,21 @@ to each distinct REM command.
|
||||
.PP
|
||||
The \fBDURATION\fR keyword makes sense only for timed reminders; it
|
||||
specifies the duration of an event. For example, if you have a
|
||||
90-minute meeting starting at 1:00pm, you could use:
|
||||
90-minute meeting starting at 1:00pm, you could use any of the following:
|
||||
.PP
|
||||
.nf
|
||||
REM 5 March 1999 AT 13:00 DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 13:00 DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 13:00 DURATION 90 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
|
||||
.fi
|
||||
.PP
|
||||
Note that \fIduration\fR is specified in hours and minutes. If you
|
||||
specify a duration of 00:00, then \fBRemind\fR behaves exactly as if
|
||||
no \fBDURATION\fR at all had been present.
|
||||
|
||||
Note that \fIduration\fR is specified either in hours and minutes as a
|
||||
\fItime\fR, or in minutes as an \fIinteger\fR. If you specify a
|
||||
duration of 00:00 or 0, then \fBRemind\fR behaves exactly as if no
|
||||
\fBDURATION\fR at all had been present.
|
||||
|
||||
.PP
|
||||
.SH THE SUBSTITUTION FILTER
|
||||
.PP
|
||||
@@ -1311,7 +1337,7 @@ is similar to \fB%3\fR but displays the current time.
|
||||
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"
|
||||
See "CALENDAR MODE"
|
||||
.PP
|
||||
Notes:
|
||||
.TP
|
||||
@@ -1665,13 +1691,15 @@ in C.
|
||||
.RE
|
||||
.TP
|
||||
.B TIME constants
|
||||
12:33, 0:01, 14:15, 16:42, 12.16, 13.00, 1.11
|
||||
12:33, 0:01, 14:15, 16:42, 12.16, 13.00, 1.11, 4:30PM, 12:20am
|
||||
.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.)
|
||||
Note that \fBTIME\fR constants may be written in 24-hour format or in
|
||||
common "AM/PM" format. If you use "AM/PM" format, then the hour can
|
||||
range from 1 to 12. Either a period or colon can be used to separate
|
||||
the minutes from the hours. However, Remind will consistently output
|
||||
times in 24-hour format using only one separator character. (The
|
||||
output separator character is chosen at compile-time.)
|
||||
.RE
|
||||
.TP
|
||||
.B DATE constants
|
||||
@@ -1694,11 +1722,12 @@ 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:
|
||||
\fBDATETIME\fR constants are expressed similarly to \fBDATE\fR
|
||||
constants with the addition of an "@HH:MM" part, optionally followed
|
||||
by "am" or "pm". For example:
|
||||
.PP
|
||||
.RS
|
||||
\'2008-04-05@23:11', '1999/02/03@14:06', '2001-04-07@08:30'
|
||||
\'2008-04-05@23:11', '1999/02/03@14:06', '2001-04-07@08:30', '2020-01-01@3:20pm'
|
||||
.PP
|
||||
\fBDATETIME\fR values are printed without the quotes. Notes about date
|
||||
and time separator characters for \fBDATE\fR and \fBTIME\fR constants apply
|
||||
@@ -1839,6 +1868,11 @@ otherwise.
|
||||
.PP
|
||||
.B NOTES
|
||||
.PP
|
||||
If the result of an addition, subtraction or multiplication operation
|
||||
would not fit in a C "int" type, \fBRemind\fR issues a "Number too
|
||||
high" error. Unlike C, integer operations will not simply give the
|
||||
wrong answer in case of overflow.
|
||||
.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.
|
||||
@@ -1885,6 +1919,9 @@ variable. Examples:
|
||||
Note that variables themselves have no type. They take on the type of
|
||||
whatever you store in them.
|
||||
.PP
|
||||
Variables set with SET or on the command-line with \fB\-i\fR\fIvar\fB=\fR\fIexpr\fR
|
||||
have global scope.
|
||||
.PP
|
||||
To delete a variable, use the \fBUNSET\fR command:
|
||||
.PP
|
||||
\fBUNSET\fR \fIvar\fR [\fIvar\fR...]
|
||||
@@ -2011,9 +2048,11 @@ 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.
|
||||
reminders. The default is the width of the terminal in columns, minus
|
||||
8, but clamped at a minimum of 20 and a maximum of 500. If standard
|
||||
output is not a terminal, then 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.
|
||||
@@ -2026,6 +2065,14 @@ then \fBONCE\fR directives will be ignored.
|
||||
.B $InfDelta (read-only)
|
||||
If non-zero, then the \fB\-t\fR option was supplied on the command line.
|
||||
.TP
|
||||
.B $IntMax (read-only)
|
||||
The largest representable \fBINT\fR. On a machine with 32-bit signed integers
|
||||
using twos-complement representation, this will be 2147483647.
|
||||
.TP
|
||||
.B $IntMin (read-only)
|
||||
The smallest representable \fBINT\fR. On a machine with 32-bit signed integers
|
||||
using twos-complement representation, this will be -2147483648.
|
||||
.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
|
||||
@@ -2042,8 +2089,13 @@ the latitude and longitude system variables.
|
||||
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.
|
||||
same sign: All positive for Western longitudes and all negative for
|
||||
Eastern longitudes. Note that for historical reasons, the sign for
|
||||
longitude is \fIdifferent\fR from the usual convention! If you find
|
||||
the longitude of your location from a search engine, you will most
|
||||
likely \fIneed to invert the sign to have it work correctly with
|
||||
Remind.\fR
|
||||
|
||||
.RS
|
||||
.PP
|
||||
The latitude and longitude information is required for the functions
|
||||
@@ -2206,6 +2258,23 @@ is supplied, only the date component is used.
|
||||
Returns the time of "astronomical twilight" on the specified \fIdate\fR. If
|
||||
\fIdate\fR is omitted, defaults to \fBtoday()\fR.
|
||||
.TP
|
||||
.B ampm(tq_time [,s_am [,s_pm]])
|
||||
Returns a \fBSTRING\fR that is the result of converting \fItime\fR
|
||||
(which is either a \fBTIME\R or a \fBDATETIME\fR object) to "AM/PM"
|
||||
format. The optional arguments \fIam\fR and \fIpm\fR are the strings
|
||||
to append in the AM and PM case, respectively; they default to "AM"
|
||||
and "PM". The function obeys the system variables $DateSep,
|
||||
$TimeSep and $DateTimeSep when formatting its output. For example:
|
||||
.RS
|
||||
.PP
|
||||
.nf
|
||||
ampm(0:22) returns "12:22AM"
|
||||
ampm(17:45, "am", "pm") returns "5:45pm"
|
||||
ampm('2020-03-14@21:34') returns "2020-03-14@9:34PM"
|
||||
.fi
|
||||
.PP
|
||||
.RE
|
||||
.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
|
||||
@@ -2452,16 +2521,16 @@ 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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
Support for Hebrew dates - see the section "THE HEBREW CALENDAR"
|
||||
.TP
|
||||
.B hour(tq_time)
|
||||
Returns the hour component of \fItime\fR.
|
||||
@@ -3115,12 +3184,12 @@ is an implementation artifact.
|
||||
.B SELF-OVERLAPPING EVENTS
|
||||
.PP
|
||||
A multi-day event has the possibility of "overlapping itself". When this
|
||||
happens, \fBRemind\fR prefers the \fIearlier\fR event (only one copy of
|
||||
happens, \fBRemind\fR prefers the \fIlater\fR event (only one copy of
|
||||
an event is ever triggered for a given date.) Consider this example:
|
||||
.PP
|
||||
.nf
|
||||
#!/bin/sh
|
||||
remind - '*4' 11 Feb 1991 <<'EOF'
|
||||
remind - '*5' 10 Feb 1991 <<'EOF'
|
||||
|
||||
BANNER %
|
||||
REM MON at 0:00 DURATION 192:0 MSG [today()] [trigeventstart()] [trigduration()]%
|
||||
@@ -3131,17 +3200,16 @@ an event is ever triggered for a given date.) Consider this example:
|
||||
The output is:
|
||||
.PP
|
||||
.nf
|
||||
1991-02-11 1991-02-04@00:00 24:00
|
||||
1991-02-10 1991-02-04@00:00 48:00
|
||||
1991-02-11 1991-02-11@00:00 192:00
|
||||
1991-02-12 1991-02-11@00:00 168:00
|
||||
1991-02-13 1991-02-11@00:00 144:00
|
||||
1991-02-14 1991-02-11@00:00 120:00
|
||||
.fi
|
||||
.PP
|
||||
Although 1991-02-11 is a Monday (which should cause the event to be
|
||||
triggered, the 8-day-long event that started on 1991-02-04 \fIhas not
|
||||
finished yet\fR, so that is the one that is triggered. The next day,
|
||||
the event starting on 1991-02-04 \fIhas\fR finished, so the 1991-02-11
|
||||
event triggers, with a remaining duration of 168:00, or 7 days.
|
||||
Although the event from 1991-02-04 still has 24 hours left on 1991-02-11,
|
||||
the fresh occurrence on 1991-02-11 takes precedences and is the one that
|
||||
is triggered.
|
||||
.PP
|
||||
I do not recommend constructing self-overlapping multi-day events.
|
||||
.PP
|
||||
@@ -3591,7 +3659,7 @@ 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.")
|
||||
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.
|
||||
@@ -3627,6 +3695,35 @@ 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 POSSIBLY-UNCOMPUTABLE TRIGGERS
|
||||
.PP
|
||||
Occasionally, you may wish to suppress the "Can't compute trigger" warnings
|
||||
for reminders for which a trigger date cannot be computed. For example,
|
||||
the following reminder is triggered on a Monday that is not a holiday
|
||||
if the following Tuesday is a holiday:
|
||||
.PP
|
||||
.nf
|
||||
REM Mon SKIP SATISFY [isomitted($T+1)] MSG Work between holidays
|
||||
.fi
|
||||
.PP
|
||||
However, if there are no Mondays after today's date that satisfy the
|
||||
condition, Remind will print the "Can't compute trigger" error. To
|
||||
suppress this, use the \fBMAYBE-UNCOMPUTABLE\fR keyword:
|
||||
.PP
|
||||
.nf
|
||||
REM MAYBE-UNCOMPUTABLE Mon SKIP SATISFY [isomitted($T+1)] MSG Work between holidays
|
||||
.fi
|
||||
.PP
|
||||
It's almost never appropriate to use \fBMAYBE-UNCOMPUTABLE\fR, but it is
|
||||
provided for those rare occasions when it makes sense. If you use
|
||||
\fBMAYBE-UNCOMPUTABLE\fR inside the \fBevaltrig()\fR function, then
|
||||
untriggerable triggers return -1. For example:
|
||||
.PP
|
||||
.nf
|
||||
SET a evaltrig("MAYBE-UNCOMPUTABLE Mon SKIP OMIT Mon")
|
||||
.fi
|
||||
.PP
|
||||
will set a to -1.
|
||||
.SH DEBUGGING REMINDER SCRIPTS
|
||||
.PP
|
||||
Although the command-line \fB\-d\fR option is useful for debugging, it
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
.TH TKREMIND 1 "1 January 2020"
|
||||
.TH TKREMIND 1 "15 January 2021"
|
||||
.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]
|
||||
.B tkremind \fR[\fIoptions\fR] [\fIread_file\fR] [\fIwrite_file\fR] [\fIconfig_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
|
||||
@@ -13,8 +13,10 @@ Although not all of \fBRemind\fR's features are available with \fBTkRemind\fR,
|
||||
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.
|
||||
\fBTkRemind\fR is written in Tcl, and requires version 8.5 (or higher)
|
||||
as well as the tcllib extension. It also requires a \fBwish\fR
|
||||
binary. If you are using Tcl/Tk 8.5, you may also need either the Img
|
||||
or the tkpng extension to handle PNG images.
|
||||
|
||||
.SH OPTIONS
|
||||
\fBTkRemind\fR itself has no options. However, it passes certain options
|
||||
@@ -41,6 +43,9 @@ include the line:
|
||||
.fi
|
||||
.PP
|
||||
|
||||
\fIConfig_file\fR is the file in which \fBTkRemind\fR stores
|
||||
its options. If it is omitted, it defaults to \fI$HOME/.tkremindrt\fR.
|
||||
|
||||
.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
|
||||
@@ -51,11 +56,14 @@ 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.
|
||||
or \fB\->\fR button, respectively. You can also use the left/right arrow
|
||||
keys or PageUp/PageDown to navigate.
|
||||
|
||||
To change back to the current month, click \fBToday\fR or press the
|
||||
Home key. 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.
|
||||
|
||||
@@ -125,10 +133,11 @@ Select the appropriate paper size and orientation. Activate
|
||||
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.
|
||||
Finally, click \fBPrint\fR to print or \fBCancel\fR to cancel. Note
|
||||
that during printing, \fBRemind\fR is called with the
|
||||
\fB-itkremind=1\fR option and also an additional \fB-itkprint=1\fR
|
||||
option.
|
||||
|
||||
|
||||
.SH EDITING REMINDERS
|
||||
|
||||
@@ -210,7 +219,8 @@ 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.
|
||||
above. The text of the reminder is prefixed by "HH:MM ", where HH:MM
|
||||
is the time of the reminder.
|
||||
|
||||
.TP
|
||||
.B E-mail reminders here if popup not dismissed
|
||||
@@ -231,6 +241,22 @@ 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"
|
||||
|
||||
.TP
|
||||
.B Extra Argument for Remind
|
||||
This specifies any extra arguments that should be passed to Remind
|
||||
when \BTkRemind\fR invokes \fBremind\fR. Unless you know what
|
||||
you are doing, leave this blank.
|
||||
|
||||
.TP
|
||||
.B Change entry font...
|
||||
This button pops up a font selection dialog that lets you change the
|
||||
font used to draw calendar items in the calendar boxes.
|
||||
|
||||
.TP
|
||||
.B Change heading font...
|
||||
Similar to Change entry font, but applies to calendar heading
|
||||
(the month and day names and the day numbers.)
|
||||
|
||||
.PP
|
||||
Once you've configured the options the way you like them,
|
||||
press \fBApply Options\fR to put them into effect, \fBSave Options\fR
|
||||
|
||||
383
scripts/tkremind
383
scripts/tkremind
@@ -7,13 +7,31 @@
|
||||
# A cheesy graphical front/back end for Remind using Tcl/Tk
|
||||
#
|
||||
# This file is part of REMIND.
|
||||
# Copyright (C) 1992-2020 Dianne Skoll
|
||||
# Copyright (C) 1992-2021 Dianne Skoll
|
||||
#
|
||||
#--------------------------------------------------------------
|
||||
|
||||
# the next line restarts using wish \
|
||||
exec wish "$0" "$@"
|
||||
|
||||
# We need at least version 8.5 because of {*} list expansion operator
|
||||
if {[catch {package require Tcl 8.5}]} {
|
||||
puts stderr "This program requires Tcl 8.5 or higher."
|
||||
puts stderr "You have version [info tclversion]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# If it's 8.5, try using the Img or the TkPNG package to
|
||||
# get PNG support
|
||||
if {[info tclversion] == 8.5} {
|
||||
if {[catch {package require Img}]} {
|
||||
if {[catch {package require tkpng}]} {
|
||||
puts stderr "Tcl/Tk version 8.5 might require either the Img or tkpng"
|
||||
puts stderr "package to handle PNG images correctly. TkRemind may"
|
||||
puts stderr "crash because neither of these packages was found."
|
||||
}
|
||||
}
|
||||
}
|
||||
wm withdraw .
|
||||
|
||||
set Hostname [exec hostname]
|
||||
@@ -106,13 +124,6 @@ if {[catch {package require json}]} {
|
||||
missing_tcllib json
|
||||
}
|
||||
|
||||
|
||||
# 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
|
||||
@@ -155,6 +166,26 @@ set OptDescr(SMTPServer) "(String) IP address or host name of SMTP server to use
|
||||
set Option(ExtraRemindArgs) ""
|
||||
set OptDescr(ExtraRemindArgs) "(String) Extra arguments when invoking remind"
|
||||
|
||||
set Option(CalboxFont) [font actual TkFixedFont]
|
||||
set OptDescr(CalboxFont) "Font to use in calendar boxes in Tk font format"
|
||||
|
||||
set Option(HeadingFont) [font actual TkDefaultFont]
|
||||
set OptDescr(HeadingFont) "Font to use in calendar headings in Tk font format"
|
||||
|
||||
set Option(BackgroundColor) "#d9d9d9"
|
||||
set OptDescr(BackgroundColor) "Default background color of calendar boxes"
|
||||
|
||||
set Option(TextColor) "#000000"
|
||||
set OptDescr(TextColor) "Default text color in calendar boxes"
|
||||
|
||||
set Option(LabelColor) "#000000"
|
||||
set OptDescr(LabelColor) "Default label color for headings"
|
||||
|
||||
set Option(WinBackground) "#d9d9d9"
|
||||
set OptDescr(WinBackground) "Background color of calendar window"
|
||||
|
||||
set TimerUpdateForChanges ""
|
||||
|
||||
# Remind program to execute -- supply full path if you want
|
||||
set Remind "remind"
|
||||
#set Remind "/home/dfs/Remind/src/remind"
|
||||
@@ -166,8 +197,14 @@ set Rem2PS "rem2ps"
|
||||
set ReminderFile {NOSUCHFILE}
|
||||
set ReminderFile [file nativename "~/.reminders"]
|
||||
|
||||
# Default options file
|
||||
set ConfigFile ~/.tkremindrc
|
||||
|
||||
set EditorPid -1
|
||||
|
||||
# Inotify file
|
||||
set InotifyFP ""
|
||||
|
||||
# Reminder file to append to -- default
|
||||
set AppendFile {NOSUCHFILE}
|
||||
catch {set AppendFile $ReminderFile}
|
||||
@@ -218,6 +255,7 @@ set PrintDest file
|
||||
set PrintSize letter
|
||||
set PrintOrient landscape
|
||||
set PrintFill 1
|
||||
set PrintDaysRight 1
|
||||
set PrintEncoding 0
|
||||
set PrintMargins 36pt
|
||||
set PrintSmallCalendars 1
|
||||
@@ -263,9 +301,9 @@ proc Initialize {} {
|
||||
|
||||
global DayNames argc argv CommandLine ReminderFile AppendFile Remind PSCmd
|
||||
global MondayFirst TwentyFourHourMode ReminderFileModTime
|
||||
global Option
|
||||
global Option ConfigFile
|
||||
set CommandLine "|$Remind -itkremind=1 -pp -y -l EXTRA"
|
||||
set PSCmd "$Remind -pp -l EXTRA"
|
||||
set PSCmd "$Remind -itkremind=1 -itkprint=1 -pp -l EXTRA"
|
||||
set i 0
|
||||
while {$i < $argc} {
|
||||
if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} {
|
||||
@@ -289,6 +327,10 @@ proc Initialize {} {
|
||||
if {$i < $argc} {
|
||||
set AppendFile [lindex $argv $i]
|
||||
incr i
|
||||
if {$i < $argc} {
|
||||
set ConfigFile [lindex $argv $i]
|
||||
incr i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,8 +417,7 @@ proc MonitorReminderFile {} {
|
||||
# Redraw calendar and restart daemon if needed
|
||||
if {$ReminderFileModTime < $mtime} {
|
||||
set ReminderFileModTime $mtime
|
||||
FillCalWindow
|
||||
RestartBackgroundRemindDaemon
|
||||
ScheduleUpdateForChanges
|
||||
}
|
||||
}
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -447,6 +488,7 @@ proc CalEntryOffset { firstDay } {
|
||||
proc CreateCalFrame { w dayNames } {
|
||||
# Figure out reasonable height for text frames
|
||||
global SetFontsWorked
|
||||
global Option
|
||||
set h [winfo screenheight .]
|
||||
if {$h <= 480} {
|
||||
if {$SetFontsWorked} {
|
||||
@@ -461,7 +503,7 @@ proc CreateCalFrame { w dayNames } {
|
||||
}
|
||||
|
||||
global MondayFirst
|
||||
frame $w
|
||||
frame $w -background $Option(WinBackground)
|
||||
for {set i 0} {$i < 7} {incr i} {
|
||||
if {$MondayFirst} {
|
||||
set index [expr ($i+1)%7]
|
||||
@@ -469,7 +511,7 @@ proc CreateCalFrame { w dayNames } {
|
||||
set index $i
|
||||
}
|
||||
|
||||
label $w.day$i -border 1 -text [lindex $dayNames $index] -justify center
|
||||
label $w.day$i -border 1 -text [lindex $dayNames $index] -justify center -font HeadingFont -foreground $Option(LabelColor) -background $Option(WinBackground)
|
||||
grid configure $w.day$i -row 0 -column $i -sticky ew
|
||||
}
|
||||
for {set i 0} {$i < 6} {incr i} {
|
||||
@@ -477,9 +519,9 @@ proc CreateCalFrame { w dayNames } {
|
||||
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
|
||||
-state disabled -relief flat -border 0 -padx 0 -pady 0 -font HeadingFont
|
||||
text $w.t$f -width 12 -height $h -border 1 -spacing3 3 -wrap word -relief flat \
|
||||
-state disabled -takefocus 0 -cursor {}
|
||||
-state disabled -takefocus 0 -cursor {} -font CalboxFont -foreground $Option(TextColor) -background $Option(BackgroundColor)
|
||||
$w.t$f tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$f"
|
||||
$w.t$f tag bind REM <ButtonPress-3> "FireEditor $w.t$f"
|
||||
|
||||
@@ -509,18 +551,17 @@ proc CreateCalFrame { w dayNames } {
|
||||
#***********************************************************************
|
||||
proc ConfigureCalFrame { w firstDay numDays } {
|
||||
global CurMonth CurYear TodayMonth TodayYear TodayDay
|
||||
global tk_version
|
||||
global tk_version Option
|
||||
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.l$i configure -text "" -command "" -state normal -relief flat -foreground $Option(LabelColor) -background $Option(WinBackground)
|
||||
$w.l$i configure -state disabled
|
||||
balloon_add_help $w.l$i ""
|
||||
$w.t$i configure -relief flat -takefocus 0 -state normal
|
||||
$w.t$i configure -relief flat -takefocus 0 -state normal -background $Option(WinBackground)
|
||||
$w.t$i delete 1.0 end
|
||||
foreach t [$w.t$i tag names] {
|
||||
$w.t$i tag delete $t
|
||||
@@ -528,16 +569,14 @@ proc ConfigureCalFrame { w firstDay numDays } {
|
||||
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
|
||||
$w.t$i tag bind REM <ButtonPress-3> "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"
|
||||
-command "ModifyDay $d $firstDay" -foreground $Option(LabelColor) -background $Option(WinBackground)
|
||||
balloon_add_help $w.l$i "Add a reminder..."
|
||||
$w.t$i configure -relief sunken -takefocus 1 -state normal
|
||||
$w.t$i configure -relief sunken -takefocus 1 -state normal -foreground $Option(TextColor) -background $Option(BackgroundColor)
|
||||
$w.t$i delete 1.0 end
|
||||
foreach t [$w.t$i tag names] {
|
||||
$w.t$i tag delete $t
|
||||
@@ -545,8 +584,6 @@ proc ConfigureCalFrame { w firstDay numDays } {
|
||||
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
|
||||
$w.t$i tag bind REM <ButtonPress-3> "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} {
|
||||
@@ -559,11 +596,13 @@ proc ConfigureCalFrame { w firstDay numDays } {
|
||||
grid rowconfigure $w $row -weight 0
|
||||
grid rowconfigure $w [expr $row+1] -weight 0
|
||||
} else {
|
||||
grid $w.l$i $w.t$i
|
||||
grid rowconfigure $w [expr $row+1] -weight 1
|
||||
}
|
||||
$w.l$i configure -text "" -command "" -state disabled -relief flat
|
||||
$w.l$i configure -text "" -command "" -state normal -relief flat -foreground $Option(LabelColor) -background $Option(WinBackground)
|
||||
$w.l$i configure -state disabled
|
||||
balloon_add_help $w.l$i ""
|
||||
$w.t$i configure -relief flat -takefocus 0 -state normal
|
||||
$w.t$i configure -relief flat -takefocus 0 -state normal -background $Option(WinBackground)
|
||||
$w.t$i delete 1.0 end
|
||||
foreach t [$w.t$i tag names] {
|
||||
$w.t$i tag delete $t
|
||||
@@ -571,8 +610,6 @@ proc ConfigureCalFrame { w firstDay numDays } {
|
||||
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
|
||||
$w.t$i tag bind REM <ButtonPress-3> "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]
|
||||
@@ -582,7 +619,7 @@ proc ConfigureCalFrame { w firstDay numDays } {
|
||||
|
||||
proc DoQueue {} {
|
||||
global DaemonFile
|
||||
puts $DaemonFile "QUEUE"
|
||||
puts $DaemonFile "JSONQUEUE"
|
||||
flush $DaemonFile
|
||||
}
|
||||
|
||||
@@ -593,14 +630,14 @@ proc DoQueue {} {
|
||||
#---------------------------------------------------------------------------
|
||||
proc CreateCalWindow { dayNames } {
|
||||
global Option
|
||||
frame .h
|
||||
label .h.title -text "" -justify center -pady 1 -border 1 -relief raised
|
||||
frame .h -background $Option(WinBackground);
|
||||
label .h.title -text "" -justify center -pady 1 -border 1 -relief raised -font HeadingFont -background $Option(WinBackground) -foreground $Option(LabelColor)
|
||||
pack .h.title -side top -fill x
|
||||
pack .h -side top -expand 0 -fill x
|
||||
|
||||
CreateCalFrame .cal $dayNames
|
||||
|
||||
frame .b
|
||||
frame .b -background $Option(WinBackground);
|
||||
button .b.prev -image leftarrow -width 24 -command {MoveMonth -1} -border 1
|
||||
balloon_add_help .b.prev "Go to previous month"
|
||||
button .b.this -text {Today} -command {ThisMonth} -border 1
|
||||
@@ -635,6 +672,7 @@ proc CreateCalWindow { dayNames } {
|
||||
bind . <KeyPress-Next> ".b.next flash; .b.next invoke"
|
||||
bind . <KeyPress-Home> ".b.this flash; .b.this invoke"
|
||||
|
||||
. configure -background $Option(WinBackground)
|
||||
if {$Option(StartIconified)} {
|
||||
wm iconify .
|
||||
}
|
||||
@@ -736,6 +774,30 @@ proc EditOptions {} {
|
||||
pack $w.extraargs -in $w.eaf -side left -expand 1 -fill x
|
||||
$w.extraargs insert 0 $tmpOpt(ExtraRemindArgs)
|
||||
|
||||
# Fonts
|
||||
frame $w.fframe
|
||||
button $w.font -text "Change entry font..." -command "ChooseCalboxFont"
|
||||
button $w.hfont -text "Change heading font..." -command "ChooseHeadingFont"
|
||||
pack $w.font $w.hfont -in $w.fframe -side left -expand 1 -fill x
|
||||
|
||||
# Colors
|
||||
frame $w.colors1
|
||||
label $w.textcolor -text "Text Color:"
|
||||
button $w.btextcolor -background $Option(TextColor) -command [list PickColor TextColor $w.btextcolor] -text ...
|
||||
label $w.bgcolor -text " Background color:"
|
||||
button $w.bbgcolor -background $Option(BackgroundColor) -command [list PickColor BackgroundColor $w.bbgcolor] -text ...
|
||||
|
||||
grid $w.textcolor $w.btextcolor $w.bgcolor $w.bbgcolor -in $w.colors1
|
||||
grid $w.bgcolor $w.bbgcolor -in $w.colors1
|
||||
|
||||
label $w.headcolor -text "Heading Color:"
|
||||
button $w.bheadcolor -background $Option(LabelColor) -command [list PickColor LabelColor $w.bheadcolor] -text ...
|
||||
label $w.wincolor -text " Window color:"
|
||||
button $w.bwincolor -background $Option(WinBackground) -command [list PickColor WinBackground $w.bwincolor] -text ...
|
||||
grid $w.headcolor $w.bheadcolor $w.wincolor $w.bwincolor -in $w.colors1
|
||||
|
||||
grid columnconfigure $w.colors1 0 -weight 1
|
||||
grid columnconfigure $w.colors1 2 -weight 1
|
||||
frame $w.sep1 -border 1 -relief sunken
|
||||
frame $w.sep2 -border 1 -relief sunken
|
||||
|
||||
@@ -757,16 +819,23 @@ proc EditOptions {} {
|
||||
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.eaf -in $w.f -side top -expand 0 -fill x
|
||||
pack $w.fframe -in $w.f -side top -expand 0 -fill x
|
||||
pack $w.colors1 -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
|
||||
button $w.cancel -text "Cancel" -command "CancelOptions; destroy $w"
|
||||
wm protocol $w WM_DELETE_WINDOW "CancelOptions; destroy $w"
|
||||
pack $w.save $w.cancel -in $w.b -side left -expand 0 -fill x
|
||||
CenterWindow $w .
|
||||
}
|
||||
|
||||
proc CancelOptions { } {
|
||||
global Option
|
||||
font configure CalboxFont {*}$Option(CalboxFont)
|
||||
font configure HeadingFont {*}$Option(HeadingFont)
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: ApplyOptions
|
||||
# %ARGUMENTS:
|
||||
@@ -807,15 +876,15 @@ proc ApplyOptions { w } {
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Saves options in $HOME/.tkremindrc
|
||||
# Saves options in specified config file
|
||||
#***********************************************************************
|
||||
proc SaveOptions { w } {
|
||||
global Option OptDescr
|
||||
global Option OptDescr ConfigFile
|
||||
ApplyOptions $w
|
||||
|
||||
set problem [catch {set f [open ~/.tkremindrc "w"]} err]
|
||||
set problem [catch {set f [open $ConfigFile "w"]} err]
|
||||
if {$problem} {
|
||||
tk_dialog .error Error "Can't write ~/.tkremindrc: $err" 0 OK
|
||||
tk_dialog .error Error "Can't write $ConfigFile: $err" 0 OK
|
||||
return
|
||||
}
|
||||
|
||||
@@ -831,6 +900,11 @@ proc SaveOptions { w } {
|
||||
}
|
||||
puts $f ""
|
||||
close $f
|
||||
FillCalWindow
|
||||
.h.title configure -background $Option(WinBackground) -foreground $Option(LabelColor)
|
||||
for {set i 0} {$i < 7} {incr i} {
|
||||
.cal.day$i configure -foreground $Option(LabelColor) -background $Option(WinBackground)
|
||||
}
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
@@ -840,25 +914,31 @@ proc SaveOptions { w } {
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Loads options from ~/.tkremindrc
|
||||
# Loads options from $ConfigFile
|
||||
#***********************************************************************
|
||||
proc LoadOptions {} {
|
||||
global Option
|
||||
set problem [catch {set f [open "~/.tkremindrc" "r"]}]
|
||||
global Option ConfigFile
|
||||
set problem [catch {set f [open "$ConfigFile" "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
|
||||
if {[string match "#*" $line]} {
|
||||
continue
|
||||
}
|
||||
if {$line == ""} {
|
||||
continue
|
||||
}
|
||||
foreach {key val} $line {}
|
||||
if {![info exists Option($key)]} {
|
||||
puts stderr "Unknown option in $ConfigFile: $key"
|
||||
continue
|
||||
}
|
||||
set Option($key) $val
|
||||
}
|
||||
close $f
|
||||
font configure CalboxFont {*}$Option(CalboxFont)
|
||||
font configure HeadingFont {*}$Option(HeadingFont)
|
||||
}
|
||||
|
||||
|
||||
@@ -962,7 +1042,8 @@ proc FillCalWindow {} {
|
||||
"WEEK" {
|
||||
set stuff [string trimleft $stuff]
|
||||
set stuff [string trimright $stuff]
|
||||
set label [expr $firstWkday + $day - 1]
|
||||
set offset [CalEntryOffset $firstWkday]
|
||||
set label [expr $offset + $day]
|
||||
.cal.l$label configure -text "$day $stuff"
|
||||
continue
|
||||
}
|
||||
@@ -1077,7 +1158,7 @@ proc Status { stuff } {
|
||||
# None
|
||||
#---------------------------------------------------------------------------
|
||||
proc DoPrint {} {
|
||||
global PrintDest PrintSize PrintMargins PrintOrient PrintFill PrintEncoding PrintSmallCalendars PrintStatus Rem2PS PSCmd Option
|
||||
global PrintDest PrintSize PrintMargins PrintOrient PrintFill PrintDaysRight PrintEncoding PrintSmallCalendars PrintStatus Rem2PS PSCmd Option
|
||||
global CurMonth CurYear MonthNames
|
||||
catch {destroy .p}
|
||||
toplevel .p
|
||||
@@ -1113,6 +1194,7 @@ proc DoPrint {} {
|
||||
radiobutton .p.portrait -text "Portrait" -variable PrintOrient -value portrait
|
||||
|
||||
checkbutton .p.fill -text "Fill page" -variable PrintFill
|
||||
checkbutton .p.right -text "Day numbers at top-right" -variable PrintDaysRight
|
||||
checkbutton .p.encoding -text "ISO 8859-1 PostScript encoding" -variable PrintEncoding
|
||||
checkbutton .p.calendars -text "Print small calendars" -variable PrintSmallCalendars
|
||||
|
||||
@@ -1121,7 +1203,7 @@ proc DoPrint {} {
|
||||
|
||||
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 \
|
||||
pack .p.fill .p.right .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
|
||||
@@ -1193,6 +1275,9 @@ proc DoPrint {} {
|
||||
append cmd " -e"
|
||||
}
|
||||
|
||||
if {!$PrintDaysRight} {
|
||||
append cmd " -x"
|
||||
}
|
||||
if {$PrintEncoding} {
|
||||
append cmd " -i"
|
||||
}
|
||||
@@ -1295,15 +1380,20 @@ proc DoGoto {} {
|
||||
#---------------------------------------------------------------------------
|
||||
proc Quit {} {
|
||||
global Option
|
||||
global InotifyFP
|
||||
if { !$Option(ConfirmQuit) } {
|
||||
destroy .
|
||||
StopBackgroundRemindDaemon
|
||||
exit
|
||||
catch { exec kill [pid $InotifyFP] }
|
||||
catch { close $InotifyFP }
|
||||
exit 0
|
||||
}
|
||||
if { [tk_dialog .question "Confirm..." {Really quit?} question 0 No Yes] } {
|
||||
destroy .
|
||||
StopBackgroundRemindDaemon
|
||||
exit
|
||||
catch { exec kill [pid $InotifyFP] }
|
||||
catch { close $InotifyFP }
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1776,8 +1866,7 @@ proc ModifyDay {d firstDay} {
|
||||
WriteReminder $f TKTAG$HighestTagSoFar $rem $opts
|
||||
close $f
|
||||
|
||||
FillCalWindow
|
||||
RestartBackgroundRemindDaemon
|
||||
ScheduleUpdateForChanges
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -2340,8 +2429,12 @@ proc BrowseForFileRead {w {dir ""}} {
|
||||
# Starts a background Remind daemon to handle timed reminders
|
||||
#---------------------------------------------------------------------------
|
||||
proc StartBackgroundRemindDaemon {} {
|
||||
global Remind DaemonFile ReminderFile Option
|
||||
set problem [catch { set DaemonFile [open "|$Remind -z0 $Option(ExtraRemindArgs) $ReminderFile" "r+"] } err]
|
||||
global Remind DaemonFile ReminderFile Option TwentyFourHourMode
|
||||
if {$TwentyFourHourMode} {
|
||||
set problem [catch { set DaemonFile [open "|$Remind -b1 -z0 -itkremind=1 $Option(ExtraRemindArgs) $ReminderFile" "r+"] } err]
|
||||
} else {
|
||||
set problem [catch { set DaemonFile [open "|$Remind -z0 -itkremind=1 $Option(ExtraRemindArgs) $ReminderFile" "r+"] } err]
|
||||
}
|
||||
if {$problem} {
|
||||
tk_dialog .error Error "Can't start Remind daemon in background: $err" error 0 OK
|
||||
} else {
|
||||
@@ -2418,18 +2511,19 @@ proc ShowQueue { file } {
|
||||
grid columnconfigure $w 1 -weight 0
|
||||
grid rowconfigure $w 0 -weight 1
|
||||
grid rowconfigure $w 1 -weight 0
|
||||
set did 0
|
||||
CenterWindow $w .
|
||||
while (1) {
|
||||
# We should only get one line
|
||||
gets $file line
|
||||
if {$line == "NOTE endqueue"} {
|
||||
if {$line == "NOTE ENDJSONQUEUE"} {
|
||||
break
|
||||
}
|
||||
set did 1
|
||||
$w.t insert end "$line\n"
|
||||
}
|
||||
if {!$did} {
|
||||
$w.t insert end "*** Queue is empty ***\n"
|
||||
if {[catch {set obj [::json::json2dict $line]}]} {
|
||||
continue;
|
||||
}
|
||||
foreach q $obj {
|
||||
$w.t insert end "$q\n"
|
||||
}
|
||||
}
|
||||
$w.t configure -state disabled
|
||||
}
|
||||
@@ -2456,7 +2550,7 @@ proc DaemonReadable { file } {
|
||||
scan $line "NOTE reminder %s %s %s" time now tag
|
||||
IssueBackgroundReminder $file $time $now $tag
|
||||
}
|
||||
"NOTE queue" {
|
||||
"NOTE JSONQUEUE" {
|
||||
ShowQueue $file
|
||||
}
|
||||
"NOTE newdate" {
|
||||
@@ -2479,7 +2573,7 @@ proc DaemonReadable { file } {
|
||||
}
|
||||
}
|
||||
default {
|
||||
puts "Unknown message from daemon: $line\n"
|
||||
puts stderr "Unknown message from daemon: $line\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2558,7 +2652,7 @@ proc IssueBackgroundReminder { file time now tag } {
|
||||
}
|
||||
if {$Option(RunCmd) != ""} {
|
||||
if {$Option(FeedReminder)} {
|
||||
FeedReminderToCommand $Option(RunCmd) $msg
|
||||
FeedReminderToCommand $Option(RunCmd) "$time: $msg"
|
||||
} else {
|
||||
exec "/bin/sh" "-c" $Option(RunCmd) "&"
|
||||
}
|
||||
@@ -2607,27 +2701,33 @@ proc CommandWritable { f msg } {
|
||||
|
||||
|
||||
proc main {} {
|
||||
# If no ~/.tkremindrc file, create an empty one
|
||||
if {![file exists ~/.tkremindrc]} {
|
||||
catch {
|
||||
set f [open ~/.tkremindrc "w"]
|
||||
close $f
|
||||
}
|
||||
}
|
||||
global ConfigFile
|
||||
|
||||
font create CalboxFont {*}[font actual TkFixedFont]
|
||||
font create HeadingFont {*}[font actual TkDefaultFont]
|
||||
|
||||
global AppendFile HighestTagSoFar DayNames
|
||||
catch {
|
||||
puts "\nTkRemind Copyright (C) 1996-2020 Dianne Skoll"
|
||||
puts "\nTkRemind Copyright (C) 1996-2021 Dianne Skoll"
|
||||
}
|
||||
catch { SetFonts }
|
||||
Initialize
|
||||
|
||||
# If no $ConfigFile file, create an empty one
|
||||
if {![file exists $ConfigFile]} {
|
||||
catch {
|
||||
set f [open $ConfigFile "w"]
|
||||
close $f
|
||||
}
|
||||
}
|
||||
LoadOptions
|
||||
CreateMoonImages
|
||||
Initialize
|
||||
ShowTodaysReminders
|
||||
ScanForTags $AppendFile
|
||||
CreateCalWindow $DayNames
|
||||
FillCalWindow
|
||||
StartBackgroundRemindDaemon
|
||||
SetupInotify
|
||||
DisplayTimeContinuously
|
||||
}
|
||||
|
||||
@@ -2704,9 +2804,11 @@ proc ReadTaggedOptions { tag date } {
|
||||
lappend ans -text-day2 $d
|
||||
}
|
||||
if {[dict exists $obj m]} {
|
||||
lappend ans -text-mon1 [lindex $MonthNames [expr [dict get $obj m] -1]]
|
||||
lappend ans -text-mon2 [lindex $MonthNames [expr [dict get $obj m] -1]]
|
||||
lappend ans -text-mon3 [lindex $MonthNames [expr [dict get $obj m] -1]]
|
||||
set mm [dict get $obj m]
|
||||
set mm [string trimleft $m 0]
|
||||
lappend ans -text-mon1 [lindex $MonthNames [expr $mm -1]]
|
||||
lappend ans -text-mon2 [lindex $MonthNames [expr $mm -1]]
|
||||
lappend ans -text-mon3 [lindex $MonthNames [expr $mm -1]]
|
||||
} else {
|
||||
lappend ans -text-mon1 {every month}
|
||||
lappend ans -text-mon2 {every month}
|
||||
@@ -2745,7 +2847,8 @@ proc ReadTaggedOptions { tag date } {
|
||||
lappend ans -text-ordinal Last
|
||||
# Adjust month down and possibly year?
|
||||
if {[dict exists $obj m]} {
|
||||
set idx [expr [dict get $obj m] -1]
|
||||
set mm [string trimleft [dict get $obj m] 0]
|
||||
set idx [expr $mm -1]
|
||||
if {$idx <= 0} {
|
||||
set idx 12
|
||||
}
|
||||
@@ -2791,15 +2894,18 @@ proc ReadTaggedOptions { tag date } {
|
||||
if {[dict exists $obj until]} {
|
||||
set u [dict get $obj until]
|
||||
regexp {^([0-9][0-9][0-9][0-9]).([0-9][0-9]).([0-9][0-9])} $u all yu mu du
|
||||
# Trim leading zeros, or Tcl complains
|
||||
set mu [string trimleft $mu 0]
|
||||
lappend ans -global-expbut 1
|
||||
lappend ans -text-expday $du
|
||||
lappend ans -text-expmon [lindex $MonthNames [expr $mu-1]]
|
||||
lappend ans -text-expyear $yu
|
||||
|
||||
} else {
|
||||
set mm [string trimleft $m 0]
|
||||
lappend ans -global-expbut 0
|
||||
lappend ans -text-expday $d
|
||||
lappend ans -text-expmon [lindex $MonthNames [expr $m-1]]
|
||||
lappend ans -text-expmon [lindex $MonthNames [expr $mm-1]]
|
||||
lappend ans -text-expyear $y
|
||||
}
|
||||
|
||||
@@ -3036,12 +3142,13 @@ proc TaggedEnter { w } {
|
||||
# Removes highlight from an "editable" reminder as mouse leaves it
|
||||
#***********************************************************************
|
||||
proc TaggedLeave { w } {
|
||||
global Option
|
||||
set tag [GetCurrentReminder $w]
|
||||
if {$tag != ""} {
|
||||
set tags [$w tag names current]
|
||||
set index [lsearch -glob $tags "clr*"]
|
||||
if {$index < 0} {
|
||||
set fg "#000000"
|
||||
set fg $Option(TextColor)
|
||||
} else {
|
||||
set fg [string range [lindex $tags $index] 3 end]
|
||||
set fg "#$fg"
|
||||
@@ -3122,12 +3229,38 @@ proc EditTaggedReminder { w } {
|
||||
return 1
|
||||
}
|
||||
|
||||
FillCalWindow
|
||||
RestartBackgroundRemindDaemon
|
||||
ScheduleUpdateForChanges
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: UpdateForChanges
|
||||
# Updates the calendar window and restarts background daemon because
|
||||
# something has changed.
|
||||
# %ARGUMENTS:
|
||||
# None
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
#***********************************************************************
|
||||
proc UpdateForChanges {} {
|
||||
global TimerUpdateForChanges
|
||||
catch { after cancel $TimerUpdateForChanges }
|
||||
FillCalWindow
|
||||
RestartBackgroundRemindDaemon
|
||||
}
|
||||
|
||||
# Schedule an update for 100ms in the future.
|
||||
# That way, if we get a rapid succession of
|
||||
# change notifications, we (probably) only
|
||||
# end up doing one call to UpdateForChanges
|
||||
proc ScheduleUpdateForChanges {} {
|
||||
global TimerUpdateForChanges
|
||||
catch { after cancel $TimerUpdateForChanges }
|
||||
set TimerUpdateForChanges [after 100 UpdateForChanges]
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: UniqueFileName
|
||||
# %ARGUMENTS:
|
||||
@@ -3406,6 +3539,7 @@ proc ShowTodaysReminders {} {
|
||||
global Option
|
||||
global Remind
|
||||
global ReminderFile
|
||||
global TwentyFourHourMode
|
||||
if {!$Option(ShowTodaysReminders)} {
|
||||
return
|
||||
}
|
||||
@@ -3427,7 +3561,10 @@ proc ShowTodaysReminders {} {
|
||||
|
||||
# Grab the reminders
|
||||
set stuff ""
|
||||
set cmdline "|$Remind -g -q -r "
|
||||
set cmdline "|$Remind -itkremind=1 -g -q -r "
|
||||
if {$TwentyFourHourMode} {
|
||||
append cmdline "-b1 "
|
||||
}
|
||||
append cmdline $Option(ExtraRemindArgs);
|
||||
append cmdline " $ReminderFile 2>/dev/null"
|
||||
set f [open $cmdline r]
|
||||
@@ -3452,8 +3589,7 @@ proc InteractiveDeleteReminder { tag } {
|
||||
set ans [tk_dialog .error "Really Delete" "Really delete reminder?" warning 0 No Yes]
|
||||
if {$ans == 1} {
|
||||
DeleteTaggedReminder $tag
|
||||
FillCalWindow
|
||||
RestartBackgroundRemindDaemon
|
||||
ScheduleUpdateForChanges
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3506,10 +3642,35 @@ proc SetFonts {} {
|
||||
set SetFontsWorked 1
|
||||
}
|
||||
|
||||
# Set up inotify to watch for changes to reminder file/directory
|
||||
proc SetupInotify {} {
|
||||
global InotifyFP
|
||||
global ReminderFile
|
||||
set failed [catch {set InotifyFP [open "|inotifywait -q -m -e close_write -e move -e create -e delete $ReminderFile" "r"] } ]
|
||||
if {$failed} {
|
||||
# inotifywait probably not available... meh.
|
||||
return
|
||||
}
|
||||
fileevent $InotifyFP readable [list InotifyReadable $InotifyFP]
|
||||
}
|
||||
|
||||
# Called when inotifywait reports an event. Schedule a calendar update
|
||||
# and daemon reload.
|
||||
proc InotifyReadable { fp } {
|
||||
catch { set num [gets $fp line] }
|
||||
if {$num < 0} {
|
||||
catch { exec kill [pid $fp] }
|
||||
close $fp
|
||||
return
|
||||
}
|
||||
ScheduleUpdateForChanges
|
||||
}
|
||||
|
||||
### Balloon help
|
||||
set Balloon(HelpTime) 400
|
||||
set Balloon(StayTime) 3500
|
||||
set Balloon(Font) fixed
|
||||
set Balloon(MustLeave) 0
|
||||
|
||||
proc balloon_reset_timer { w } {
|
||||
balloon_destroy_help_window
|
||||
@@ -3623,4 +3784,40 @@ proc balloon_calculate_geometry { w } {
|
||||
return "+$tx+$ty"
|
||||
}
|
||||
|
||||
proc ChooseCalboxFont {} {
|
||||
tk fontchooser show
|
||||
tk fontchooser configure -font [font actual CalboxFont]
|
||||
tk fontchooser configure -command SetCalboxFont
|
||||
}
|
||||
|
||||
proc SetCalboxFont {font} {
|
||||
global tmpOpt
|
||||
font configure CalboxFont {*}[font actual $font]
|
||||
set tmpOpt(CalboxFont) [font actual $font]
|
||||
raise .opt
|
||||
}
|
||||
|
||||
proc ChooseHeadingFont {} {
|
||||
tk fontchooser show
|
||||
tk fontchooser configure -font [font actual HeadingFont]
|
||||
tk fontchooser configure -command SetHeadingFont
|
||||
}
|
||||
|
||||
proc SetHeadingFont {font} {
|
||||
global tmpOpt
|
||||
font configure HeadingFont {*}[font actual $font]
|
||||
set tmpOpt(HeadingFont) [font actual $font]
|
||||
raise .opt
|
||||
}
|
||||
|
||||
proc PickColor {index button} {
|
||||
global tmpOpt
|
||||
set x [tk_chooseColor -initialcolor $tmpOpt($index)]
|
||||
if {"$x" != ""} {
|
||||
set tmpOpt($index) $x
|
||||
$button configure -background $x
|
||||
}
|
||||
raise .opt
|
||||
}
|
||||
|
||||
main
|
||||
|
||||
@@ -86,7 +86,7 @@ distro:
|
||||
gpg --detach-sign -u dianne@skoll.ca remind-$(VERSION).tar.gz
|
||||
|
||||
beta-tgz:
|
||||
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)/ HEAD > src/remind-$(VERSION)-BETA-$(BETA).tar
|
||||
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)-BETA-$(BETA)/ HEAD > src/remind-$(VERSION)-BETA-$(BETA).tar
|
||||
gzip -f -v -9 remind-$(VERSION)-BETA-$(BETA).tar
|
||||
gpg --detach-sign -u dianne@skoll.ca remind-$(VERSION)-BETA-$(BETA).tar.gz
|
||||
|
||||
|
||||
132
src/calendar.c
132
src/calendar.c
@@ -9,6 +9,7 @@
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
#define _XOPEN_SOURCE
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -21,6 +22,7 @@
|
||||
|
||||
#ifdef REM_USE_WCHAR
|
||||
#include <wctype.h>
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
@@ -245,7 +247,7 @@ static void WriteBottomCalLine (void);
|
||||
static void WriteIntermediateCalLine (void);
|
||||
static void WriteCalDays (void);
|
||||
|
||||
static void PrintJSONString(char const *s)
|
||||
void PrintJSONString(char const *s)
|
||||
{
|
||||
while (*s) {
|
||||
switch(*s) {
|
||||
@@ -262,14 +264,14 @@ static void PrintJSONString(char const *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintJSONKeyPairInt(char const *name, int val)
|
||||
void PrintJSONKeyPairInt(char const *name, int val)
|
||||
{
|
||||
printf("\"");
|
||||
PrintJSONString(name);
|
||||
printf("\":%d, ", val);
|
||||
}
|
||||
|
||||
static void PrintJSONKeyPairString(char const *name, char const *val)
|
||||
void PrintJSONKeyPairString(char const *name, char const *val)
|
||||
{
|
||||
/* If value is blank, skip it! */
|
||||
if (!val || !*val) {
|
||||
@@ -283,7 +285,7 @@ static void PrintJSONKeyPairString(char const *name, char const *val)
|
||||
printf("\", ");
|
||||
}
|
||||
|
||||
static void PrintJSONKeyPairDate(char const *name, int jul)
|
||||
void PrintJSONKeyPairDate(char const *name, int jul)
|
||||
{
|
||||
int y, m, d;
|
||||
if (jul == NO_DATE) {
|
||||
@@ -297,7 +299,7 @@ static void PrintJSONKeyPairDate(char const *name, int jul)
|
||||
|
||||
}
|
||||
|
||||
static void PrintJSONKeyPairDateTime(char const *name, int dt)
|
||||
void PrintJSONKeyPairDateTime(char const *name, int dt)
|
||||
{
|
||||
int y, m, d, h, i, k;
|
||||
if (dt == NO_TIME) {
|
||||
@@ -315,6 +317,21 @@ static void PrintJSONKeyPairDateTime(char const *name, int dt)
|
||||
|
||||
}
|
||||
|
||||
void PrintJSONKeyPairTime(char const *name, int t)
|
||||
{
|
||||
int h, i;
|
||||
if (t == NO_TIME) {
|
||||
/* Skip it! */
|
||||
return;
|
||||
}
|
||||
h = t / 60;
|
||||
i = t % 60;
|
||||
printf("\"");
|
||||
PrintJSONString(name);
|
||||
printf("\":\"%02d:%02d\", ", h, i);
|
||||
|
||||
}
|
||||
|
||||
#ifdef REM_USE_WCHAR
|
||||
static void PutWideChar(wchar_t const wc)
|
||||
{
|
||||
@@ -341,6 +358,7 @@ static int make_wchar_versions(CalEntry *e)
|
||||
if (!buf) return 0;
|
||||
|
||||
(void) mbstowcs(buf, e->text, len+1);
|
||||
buf[len] = 0;
|
||||
e->wc_text = buf;
|
||||
e->wc_pos = buf;
|
||||
return 1;
|
||||
@@ -495,7 +513,7 @@ ComputeCalWidth(int x)
|
||||
return 80;
|
||||
}
|
||||
if (w.ws_col < 71) {
|
||||
return 80;
|
||||
return 71;
|
||||
}
|
||||
return w.ws_col;
|
||||
}
|
||||
@@ -778,8 +796,13 @@ static int WriteCalendarRow(void)
|
||||
if (i < wd || d+i-wd>DaysInMonth(m, y))
|
||||
PrintLeft("", ColSpaces, ' ');
|
||||
else {
|
||||
sprintf(buf, "%d", d+i-wd);
|
||||
PrintLeft(buf, ColSpaces, ' ');
|
||||
sprintf(buf, "%d ", d+i-wd);
|
||||
if (OrigJul+i == RealToday) {
|
||||
PrintLeft(buf, ColSpaces-1, '*');
|
||||
PutChar(' ');
|
||||
} else {
|
||||
PrintLeft(buf, ColSpaces, ' ');
|
||||
}
|
||||
}
|
||||
gon();
|
||||
DRAW(tb);
|
||||
@@ -861,11 +884,21 @@ static void PrintCentered(char const *s, int width, char *pad)
|
||||
|
||||
for (i=0; i<d; i++) fputs(pad, stdout);
|
||||
for (i=0; i<width; i++) {
|
||||
if (*s) PutChar(*s++); else break;
|
||||
if (*s) {
|
||||
if (isspace(*s)) {
|
||||
PutChar(' ');
|
||||
s++;
|
||||
} else {
|
||||
PutChar(*s++);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i=d+len; i<width; i++) fputs(pad, stdout);
|
||||
#else
|
||||
size_t len = mbstowcs(NULL, s, 0);
|
||||
int display_len;
|
||||
int i;
|
||||
wchar_t static_buf[128];
|
||||
wchar_t *buf;
|
||||
@@ -889,11 +922,25 @@ static void PrintCentered(char const *s, int width, char *pad)
|
||||
}
|
||||
}
|
||||
(void) mbstowcs(buf, s, len+1);
|
||||
d = (width - len) / 2;
|
||||
display_len = wcswidth(buf, len+1);
|
||||
d = (width - display_len) / 2;
|
||||
if (d < 0) d = 0;
|
||||
ws = buf;
|
||||
for (i=0; i<d; i++) fputs(pad, stdout);
|
||||
for (i=0; i<width; i++) {
|
||||
if (*ws) PutWideChar(*ws++); else break;
|
||||
if (*ws) {
|
||||
PutWideChar(*ws++);
|
||||
if (wcwidth(*ws) == 0) {
|
||||
/* Don't count this character... it's zero-width */
|
||||
i--;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Mop up any potential combining characters */
|
||||
while (*ws && wcwidth(*ws) == 0) {
|
||||
PutWideChar(*ws++);
|
||||
}
|
||||
for (i=d+len; i<width; i++) fputs(pad, stdout);
|
||||
if (buf != static_buf) free(buf);
|
||||
@@ -947,6 +994,7 @@ static int WriteOneColLine(int col)
|
||||
#ifdef REM_USE_WCHAR
|
||||
wchar_t const *ws;
|
||||
wchar_t const *wspace;
|
||||
int width;
|
||||
#endif
|
||||
|
||||
int numwritten = 0;
|
||||
@@ -971,9 +1019,18 @@ static int WriteOneColLine(int col)
|
||||
}
|
||||
|
||||
/* Find the last space char within the column. */
|
||||
while (ws - e->wc_pos <= ColSpaces) {
|
||||
if (!*ws) {wspace = ws; break;}
|
||||
if (iswspace(*ws)) wspace = ws;
|
||||
width = 0;
|
||||
while (width <= ColSpaces) {
|
||||
if (!*ws) {
|
||||
wspace = ws;
|
||||
break;
|
||||
}
|
||||
if (iswspace(*ws)) {
|
||||
wspace = ws;
|
||||
}
|
||||
if (wcwidth(*ws)) {
|
||||
width++;
|
||||
}
|
||||
ws++;
|
||||
}
|
||||
|
||||
@@ -986,16 +1043,30 @@ static int WriteOneColLine(int col)
|
||||
if (!wspace) {
|
||||
for (ws = e->wc_pos; ws - e->wc_pos < ColSpaces; ws++) {
|
||||
if (!*ws) break;
|
||||
numwritten++;
|
||||
PutWideChar(*ws);
|
||||
if (iswspace(*ws)) {
|
||||
PutChar(' ');
|
||||
numwritten++;
|
||||
} else {
|
||||
if (wcwidth(*ws) > 0) {
|
||||
numwritten += wcwidth(*ws);
|
||||
}
|
||||
PutWideChar(*ws);
|
||||
}
|
||||
}
|
||||
e->wc_pos = ws;
|
||||
} else {
|
||||
/* We found a space - print everything before it. */
|
||||
for (ws = e->wc_pos; ws<wspace; ws++) {
|
||||
if (!*ws) break;
|
||||
numwritten++;
|
||||
PutWideChar(*ws);
|
||||
if (iswspace(*ws)) {
|
||||
PutChar(' ');
|
||||
numwritten++;
|
||||
} else {
|
||||
if (wcwidth(*ws) > 0) {
|
||||
numwritten += wcwidth(*ws);
|
||||
}
|
||||
PutWideChar(*ws);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1045,7 +1116,7 @@ static int WriteOneColLine(int col)
|
||||
/* Find the last space char within the column. */
|
||||
while (s - e->pos <= ColSpaces) {
|
||||
if (!*s) {space = s; break;}
|
||||
if (*s == ' ') space = s;
|
||||
if (isspace(*s)) space = s;
|
||||
s++;
|
||||
}
|
||||
|
||||
@@ -1059,7 +1130,11 @@ static int WriteOneColLine(int col)
|
||||
for (s = e->pos; s - e->pos < ColSpaces; s++) {
|
||||
if (!*s) break;
|
||||
numwritten++;
|
||||
PutChar(*s);
|
||||
if (isspace(*s)) {
|
||||
PutChar(' ');
|
||||
} else {
|
||||
PutChar(*s);
|
||||
}
|
||||
}
|
||||
e->pos = s;
|
||||
} else {
|
||||
@@ -1067,7 +1142,11 @@ static int WriteOneColLine(int col)
|
||||
for (s = e->pos; s<space; s++) {
|
||||
if (!*s) break;
|
||||
numwritten++;
|
||||
PutChar(*s);
|
||||
if (isspace(*s)) {
|
||||
PutChar(' ');
|
||||
} else {
|
||||
PutChar(*s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1080,7 +1159,7 @@ static int WriteOneColLine(int col)
|
||||
while(numwritten++ < ColSpaces) PutChar(' ');
|
||||
|
||||
/* Skip any spaces before next word */
|
||||
while (*s == ' ') s++;
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
/* If done, free memory if no next entry. */
|
||||
if (!*s && !e->next) {
|
||||
@@ -1305,6 +1384,9 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
if (trig.typ == SAT_TYPE) {
|
||||
r=DoSatRemind(&trig, &tim, p);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = OK;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
if (r == E_EXPIRED) return OK;
|
||||
return r;
|
||||
@@ -1349,6 +1431,9 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
/* Calculate the trigger date */
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = OK;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
@@ -1579,6 +1664,7 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
if(!e->filename) {
|
||||
if (e->text) free(e->text);
|
||||
if (e->raw_text) free(e->raw_text);
|
||||
if (e->wc_text) free(e->wc_text);
|
||||
free(e);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
@@ -2081,8 +2167,6 @@ char const *SynthesizeTag(void)
|
||||
unsigned char buf[16];
|
||||
static char out[128];
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char *) FileName, strlen(FileName));
|
||||
MD5Update(&ctx, (unsigned char *) &LineNo, sizeof(LineNo));
|
||||
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",
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
/* VAR_NAME_LEN: The maximum length of variable names. Don't make it */
|
||||
/* any less than 12. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
#define VAR_NAME_LEN 16
|
||||
#define VAR_NAME_LEN 64
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* MAX_PRT_LEN: The maximum number of characters to print when */
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
/* VAR_NAME_LEN: The maximum length of variable names. Don't make it */
|
||||
/* any less than 12. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
#define VAR_NAME_LEN 16
|
||||
#define VAR_NAME_LEN 64
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* MAX_PRT_LEN: The maximum number of characters to print when */
|
||||
|
||||
34
src/dorem.c
34
src/dorem.c
@@ -81,6 +81,9 @@ int DoRem(ParsePtr p)
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
r=DoSatRemind(&trig, &tim, p);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = OK;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
if (r == E_EXPIRED) return OK;
|
||||
return r;
|
||||
@@ -134,6 +137,9 @@ int DoRem(ParsePtr p)
|
||||
PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", ErrMsg[r]);
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
}
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = OK;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
@@ -219,6 +225,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
trig->duration_days = 0;
|
||||
trig->eventstart = NO_TIME;
|
||||
trig->eventduration = NO_TIME;
|
||||
trig->maybe_uncomputable = 0;
|
||||
DBufInit(&(trig->tags));
|
||||
trig->passthru[0] = 0;
|
||||
tim->ttime = NO_TIME;
|
||||
@@ -276,6 +283,10 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
trig->m = tok.val;
|
||||
break;
|
||||
|
||||
case T_MaybeUncomputable:
|
||||
trig->maybe_uncomputable = 1;
|
||||
break;
|
||||
|
||||
case T_Skip:
|
||||
DBufFree(&buf);
|
||||
if (trig->skip != NO_SKIP) return E_SKIP_ERR;
|
||||
@@ -417,6 +428,9 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
switch(tok.type) {
|
||||
case T_Time:
|
||||
case T_LongTime:
|
||||
case T_Year:
|
||||
case T_Day:
|
||||
case T_Number:
|
||||
if (tok.val != 0) {
|
||||
tim->duration = tok.val;
|
||||
} else {
|
||||
@@ -984,7 +998,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
break;
|
||||
|
||||
case RUN_TYPE:
|
||||
system(DBufValue(&buf));
|
||||
System(DBufValue(&buf));
|
||||
break;
|
||||
|
||||
default: /* Unknown/illegal type? */
|
||||
@@ -1099,10 +1113,24 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
||||
iter = 0;
|
||||
start = trig->scanfrom;
|
||||
while (iter++ < MaxSatIter) {
|
||||
jul = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1);
|
||||
jul = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG) return OK; else return r;
|
||||
}
|
||||
if (jul != start && trig->duration_days) {
|
||||
jul = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG) return OK; else return r;
|
||||
}
|
||||
} else if (jul == start) {
|
||||
if (tt->ttime != NO_TIME) {
|
||||
trig->eventstart = MINUTES_PER_DAY * r + tt->ttime;
|
||||
if (tt->duration != NO_TIME) {
|
||||
trig->eventduration = tt->duration;
|
||||
}
|
||||
}
|
||||
SaveAllTriggerInfo(trig, tt, jul, tt->ttime, 1);
|
||||
}
|
||||
if (jul == -1) {
|
||||
return E_EXPIRED;
|
||||
}
|
||||
@@ -1240,7 +1268,7 @@ int DoMsgCommand(char const *cmd, char const *msg)
|
||||
}
|
||||
r = OK;
|
||||
|
||||
system(DBufValue(&execBuffer));
|
||||
System(DBufValue(&execBuffer));
|
||||
|
||||
finished:
|
||||
DBufFree(&buf);
|
||||
|
||||
@@ -644,10 +644,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
|
||||
break;
|
||||
|
||||
case '_':
|
||||
if (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand)
|
||||
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand)) {
|
||||
sprintf(s, "%s", NL);
|
||||
else
|
||||
} else {
|
||||
sprintf(s, " ");
|
||||
}
|
||||
SHIP_OUT(s);
|
||||
break;
|
||||
|
||||
|
||||
@@ -150,7 +150,9 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
|
||||
we can usually save some unnecessary copying */
|
||||
|
||||
*(dbuf->buffer) = 0;
|
||||
fgets(dbuf->buffer, dbuf->allocatedLen, fp);
|
||||
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
|
||||
return OK;
|
||||
}
|
||||
if (!*(dbuf->buffer)) return OK;
|
||||
dbuf->len = strlen(dbuf->buffer);
|
||||
l = dbuf->len - 1;
|
||||
@@ -162,7 +164,7 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
|
||||
|
||||
while(busy) {
|
||||
*tmp = 0;
|
||||
fgets(tmp, 256, fp);
|
||||
if (fgets(tmp, 256, fp) == NULL) return OK;
|
||||
if (!*tmp) return OK;
|
||||
l = strlen(tmp) - 1;
|
||||
if (tmp[l] == '\n') {
|
||||
|
||||
145
src/expr.c
145
src/expr.c
@@ -13,6 +13,7 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -492,6 +493,8 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
|
||||
{
|
||||
int len;
|
||||
int h, m, r;
|
||||
int ampm = 0;
|
||||
int prev_val;
|
||||
|
||||
if (*s == '\"') { /* It's a literal string "*/
|
||||
len = strlen(s)-1;
|
||||
@@ -518,9 +521,15 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
|
||||
return OK;
|
||||
} else if (isdigit(*s)) { /* It's a number - use len to hold it.*/
|
||||
len = 0;
|
||||
prev_val = 0;
|
||||
while (*s && isdigit(*s)) {
|
||||
len *= 10;
|
||||
len += (*s++ - '0');
|
||||
if (len < prev_val) {
|
||||
/* We overflowed */
|
||||
return E_2HIGH;
|
||||
}
|
||||
prev_val = len;
|
||||
}
|
||||
if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */
|
||||
s++;
|
||||
@@ -532,7 +541,27 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
|
||||
m += *s - '0';
|
||||
s++;
|
||||
}
|
||||
/* Check for p[m] or a[m] */
|
||||
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
|
||||
ampm = tolower(*s);
|
||||
s++;
|
||||
if (*s == 'm' || *s == 'M') {
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if (*s || h>23 || m>59) return E_BAD_TIME;
|
||||
if (ampm) {
|
||||
if (h < 1 || h > 12) return E_BAD_TIME;
|
||||
if (ampm == 'a') {
|
||||
if (h == 12) {
|
||||
h = 0;
|
||||
}
|
||||
} else if (ampm == 'p') {
|
||||
if (h < 12) {
|
||||
h += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
v->type = TIME_TYPE;
|
||||
v->v.val = h*60 + m;
|
||||
return OK;
|
||||
@@ -701,26 +730,12 @@ int DoCoerce(char type, Value *v)
|
||||
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;
|
||||
if (ParseLiteralTime(&s, &i)) return E_CANT_COERCE;
|
||||
if (*s) return E_CANT_COERCE;
|
||||
v->type = TIME_TYPE;
|
||||
free(v->v.str);
|
||||
v->v.val = h*60+m;
|
||||
v->v.val = i;
|
||||
return OK;
|
||||
|
||||
default: return E_CANT_COERCE;
|
||||
@@ -751,15 +766,22 @@ static int Add(void)
|
||||
|
||||
/* If both are ints, just add 'em */
|
||||
if (v2.type == INT_TYPE && v1.type == INT_TYPE) {
|
||||
v2.v.val += v1.v.val;
|
||||
PushValStack(v2);
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
/* Check for overflow */
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) {
|
||||
return E_2HIGH;
|
||||
}
|
||||
PushValStack(v1);
|
||||
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)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
v1.type = DATE_TYPE;
|
||||
PushValStack(v1);
|
||||
@@ -769,7 +791,9 @@ static int Add(void)
|
||||
/* If it's a datetime plus an int or a time, add 'em */
|
||||
if ((v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) ||
|
||||
((v1.type == INT_TYPE || v1.type == TIME_TYPE) && v2.type == DATETIME_TYPE)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
v1.type = DATETIME_TYPE;
|
||||
PushValStack(v1);
|
||||
@@ -781,7 +805,10 @@ static int Add(void)
|
||||
if ((v1.type == TIME_TYPE && v2.type == INT_TYPE) ||
|
||||
(v1.type == INT_TYPE && v2.type == TIME_TYPE) ||
|
||||
(v1.type == TIME_TYPE && v2.type == TIME_TYPE)) {
|
||||
v1.v.val = (v1.v.val + v2.v.val) % MINUTES_PER_DAY;
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
v1.v.val = v1.v.val % MINUTES_PER_DAY;
|
||||
if (v1.v.val < 0) v1.v.val += MINUTES_PER_DAY;
|
||||
v1.type = TIME_TYPE;
|
||||
PushValStack(v1);
|
||||
@@ -841,14 +868,18 @@ static int Subtract(void)
|
||||
|
||||
/* If they're both INTs, do subtraction */
|
||||
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_2HIGH;
|
||||
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) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
@@ -857,7 +888,9 @@ static int Subtract(void)
|
||||
/* If it's a datetime minus an int or a time, do subtraction,
|
||||
* checking for underflow */
|
||||
if (v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
@@ -875,7 +908,9 @@ static int Subtract(void)
|
||||
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)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
v1.type = INT_TYPE;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
@@ -905,7 +940,11 @@ static int Multiply(void)
|
||||
}
|
||||
|
||||
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val *= v2.v.val;
|
||||
if (v2.v.val != 0) {
|
||||
if (_private_div(v1.v.val, v2.v.val) != old) return E_2HIGH;
|
||||
}
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
}
|
||||
@@ -933,6 +972,10 @@ static int Divide(void)
|
||||
|
||||
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
||||
if (v2.v.val == 0) return E_DIV_ZERO;
|
||||
/* This is the only way it can overflow */
|
||||
if (v2.v.val == -1 && v1.v.val == INT_MIN) {
|
||||
return E_2HIGH;
|
||||
}
|
||||
v1.v.val /= v2.v.val;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
@@ -1107,7 +1150,9 @@ static int UnMinus(void)
|
||||
{
|
||||
Value *v = &ValStack[ValStackPtr-1];
|
||||
if (v->type != INT_TYPE) return E_BAD_TYPE;
|
||||
int old = v->v.val;
|
||||
v->v.val = -v->v.val;
|
||||
if (_private_unminus_overflow(old, v->v.val)) return E_2HIGH;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -1222,6 +1267,48 @@ int CopyValue(Value *dest, const Value *src)
|
||||
return OK;
|
||||
}
|
||||
|
||||
int ParseLiteralTime(char const **s, int *tim)
|
||||
{
|
||||
int h=0;
|
||||
int m=0;
|
||||
int ampm=0;
|
||||
if (!isdigit(**s)) return E_BAD_TIME;
|
||||
while(isdigit(**s)) {
|
||||
h *= 10;
|
||||
h += *(*s)++ - '0';
|
||||
}
|
||||
if (**s != ':' && **s != '.' && **s != TimeSep) return E_BAD_TIME;
|
||||
(*s)++;
|
||||
if (!isdigit(**s)) return E_BAD_TIME;
|
||||
while(isdigit(**s)) {
|
||||
m *= 10;
|
||||
m += *(*s)++ - '0';
|
||||
}
|
||||
/* Check for p[m] or a[m] */
|
||||
if (**s == 'A' || **s == 'a' || **s == 'P' || **s == 'p') {
|
||||
ampm = tolower(**s);
|
||||
(*s)++;
|
||||
if (**s == 'm' || **s == 'M') {
|
||||
(*s)++;
|
||||
}
|
||||
}
|
||||
if (h>23 || m>59) return E_BAD_TIME;
|
||||
if (ampm) {
|
||||
if (h < 1 || h > 12) return E_BAD_TIME;
|
||||
if (ampm == 'a') {
|
||||
if (h == 12) {
|
||||
h = 0;
|
||||
}
|
||||
} else if (ampm == 'p') {
|
||||
if (h < 12) {
|
||||
h += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
*tim = h * 60 + m;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* ParseLiteralDate */
|
||||
@@ -1233,10 +1320,9 @@ int CopyValue(Value *dest, const Value *src)
|
||||
int ParseLiteralDate(char const **s, int *jul, int *tim)
|
||||
{
|
||||
int y, m, d;
|
||||
int hour, min;
|
||||
int r;
|
||||
|
||||
y=0; m=0; d=0;
|
||||
hour=0; min=0;
|
||||
|
||||
*tim = NO_TIME;
|
||||
if (!isdigit(**s)) return E_BAD_DATE;
|
||||
@@ -1266,20 +1352,9 @@ int ParseLiteralDate(char const **s, int *jul, int *tim)
|
||||
/* Do we have a time part as well? */
|
||||
if (**s == ' ' || **s == '@' || **s == 'T' || **s == 't') {
|
||||
(*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;
|
||||
r = ParseLiteralTime(s, tim);
|
||||
if (r != OK) return r;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
11
src/expr.h
11
src/expr.h
@@ -5,7 +5,7 @@
|
||||
/* Contains a few definitions used by expression evaluator. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2020 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -53,3 +53,12 @@ if (ValStackPtr <= 0) \
|
||||
return E_VA_STK_UNDER; \
|
||||
else \
|
||||
(val) = ValStack[--ValStackPtr]
|
||||
|
||||
/* These functions are in utils.c and are used to detect overflow
|
||||
in various arithmetic operators. They have to be in separate
|
||||
functions with extern linkage to defeat compiler optimizations
|
||||
that would otherwise break the overflow checks. */
|
||||
extern int _private_div(int a, int b);
|
||||
extern int _private_add_overflow(int result, int b, int old);
|
||||
extern int _private_sub_overflow(int result, int b, int old);
|
||||
extern int _private_unminus_overflow(int a, int b);
|
||||
|
||||
@@ -366,12 +366,12 @@ static int CacheFile(char const *fname)
|
||||
cl = NULL;
|
||||
/* Create a file header */
|
||||
cf = NEW(CachedFile);
|
||||
cf->cache = NULL;
|
||||
if (!cf) {
|
||||
ShouldCache = 0;
|
||||
FCLOSE(fp);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
cf->cache = NULL;
|
||||
cf->filename = StrDup(fname);
|
||||
if (!cf->filename) {
|
||||
ShouldCache = 0;
|
||||
|
||||
80
src/funcs.c
80
src/funcs.c
@@ -57,6 +57,7 @@ static int FADawn (func_info *);
|
||||
static int FADusk (func_info *);
|
||||
static int FAbs (func_info *);
|
||||
static int FAccess (func_info *);
|
||||
static int FAmpm (func_info *);
|
||||
static int FArgs (func_info *);
|
||||
static int FAsc (func_info *);
|
||||
static int FBaseyr (func_info *);
|
||||
@@ -206,6 +207,7 @@ BuiltinFunc Func[] = {
|
||||
{ "access", 2, 2, 0, FAccess },
|
||||
{ "adawn", 0, 1, 0, FADawn},
|
||||
{ "adusk", 0, 1, 0, FADusk},
|
||||
{ "ampm", 1, 3, 1, FAmpm },
|
||||
{ "args", 1, 1, 0, FArgs },
|
||||
{ "asc", 1, 1, 1, FAsc },
|
||||
{ "baseyr", 0, 0, 1, FBaseyr },
|
||||
@@ -864,12 +866,14 @@ static int FTime(func_info *info)
|
||||
/***************************************************************/
|
||||
static int FAbs(func_info *info)
|
||||
{
|
||||
int v;
|
||||
volatile int v;
|
||||
|
||||
ASSERT_TYPE(0, INT_TYPE);
|
||||
v = ARGV(0);
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = (v < 0) ? (-v) : v;
|
||||
v = RETVAL;
|
||||
if (v < 0) return E_2HIGH;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -886,6 +890,76 @@ static int FSgn(func_info *info)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FAmpm - return a time as a string with "AM" or "PM" suffix */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int FAmpm(func_info *info)
|
||||
{
|
||||
int h, m;
|
||||
int yr=0, mo=0, da=0;
|
||||
|
||||
char const *am = "AM";
|
||||
char const *pm = "PM";
|
||||
char const *ampm = NULL;
|
||||
|
||||
char outbuf[128];
|
||||
|
||||
if (ARG(0).type != DATETIME_TYPE && ARG(0).type != TIME_TYPE) {
|
||||
return E_BAD_TYPE;
|
||||
}
|
||||
if (HASDATE(ARG(0))) {
|
||||
FromJulian(DATEPART(ARG(0)), &yr, &mo, &da);
|
||||
}
|
||||
if (Nargs >= 2) {
|
||||
ASSERT_TYPE(1, STR_TYPE);
|
||||
am = ARGSTR(1);
|
||||
if (Nargs >= 3) {
|
||||
ASSERT_TYPE(2, STR_TYPE);
|
||||
pm = ARGSTR(2);
|
||||
}
|
||||
}
|
||||
h = TIMEPART(ARG(0)) / 60;
|
||||
m = TIMEPART(ARG(0)) % 60;
|
||||
if (h <= 11) {
|
||||
/* AM */
|
||||
if (h == 0) {
|
||||
if (ARG(0).type == DATETIME_TYPE) {
|
||||
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c12%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, TimeSep, m);
|
||||
} else {
|
||||
snprintf(outbuf, sizeof(outbuf), "12%c%02d", TimeSep, m);
|
||||
}
|
||||
} else {
|
||||
if (ARG(0).type == DATETIME_TYPE) {
|
||||
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
|
||||
} else {
|
||||
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
|
||||
}
|
||||
}
|
||||
ampm = am;
|
||||
} else {
|
||||
if (h > 12) {
|
||||
h -= 12;
|
||||
}
|
||||
if (ARG(0).type == DATETIME_TYPE) {
|
||||
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
|
||||
} else {
|
||||
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
|
||||
}
|
||||
ampm = pm;
|
||||
}
|
||||
RetVal.type = STR_TYPE;
|
||||
RetVal.v.str = malloc(strlen(outbuf) + strlen(ampm) + 1);
|
||||
if (!RetVal.v.str) {
|
||||
RetVal.type = ERR_TYPE;
|
||||
return E_NO_MEM;
|
||||
}
|
||||
strcpy(RetVal.v.str, outbuf);
|
||||
strcat(RetVal.v.str, ampm);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FOrd - returns a string containing ordinal number. */
|
||||
@@ -2845,6 +2919,10 @@ FEvalTrig(func_info *info)
|
||||
}
|
||||
jul = ComputeTrigger(scanfrom, &trig, &tim, &r, 0);
|
||||
}
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = 0;
|
||||
jul = -1;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
if (r) return r;
|
||||
if (jul < 0) {
|
||||
|
||||
12
src/init.c
12
src/init.c
@@ -23,6 +23,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "protos.h"
|
||||
@@ -147,6 +148,17 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
jul = NO_DATE;
|
||||
|
||||
/* If stdout is a terminal, initialize $FormWidth to terminal width-8,
|
||||
but clamp to [20, 500] */
|
||||
if (isatty(STDOUT_FILENO)) {
|
||||
struct winsize w;
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
|
||||
FormWidth = w.ws_col - 8;
|
||||
if (FormWidth < 20) FormWidth = 20;
|
||||
if (FormWidth > 500) FormWidth = 500;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize global dynamic buffers */
|
||||
DBufInit(&Banner);
|
||||
DBufInit(&LineBuffer);
|
||||
|
||||
@@ -213,7 +213,7 @@ static int new_value (json_state * state,
|
||||
}
|
||||
|
||||
#define whitespace \
|
||||
case '\n': ++ state.cur_line; state.cur_col = 0; \
|
||||
case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \
|
||||
case ' ': case '\t': case '\r'
|
||||
|
||||
#define string_add(b) \
|
||||
|
||||
29
src/main.c
29
src/main.c
@@ -813,9 +813,11 @@ int DoIfTrig(ParsePtr p)
|
||||
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||
if (r) {
|
||||
if (!Hush || r != E_RUN_DISABLED) {
|
||||
Eprint("%s", ErrMsg[r]);
|
||||
}
|
||||
if (r != E_CANT_TRIG || !trig.maybe_uncomputable) {
|
||||
if (!Hush || r != E_RUN_DISABLED) {
|
||||
Eprint("%s", ErrMsg[r]);
|
||||
}
|
||||
}
|
||||
syndrome = IF_TRUE | BEFORE_ELSE;
|
||||
}
|
||||
else {
|
||||
@@ -1370,6 +1372,16 @@ ClearLastTriggers(void)
|
||||
LastTimeTrig.duration = NO_TIME;
|
||||
}
|
||||
|
||||
void
|
||||
SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigtime, int valid)
|
||||
{
|
||||
SaveLastTrigger(t);
|
||||
SaveLastTimeTrig(tt);
|
||||
LastTriggerDate = trigdate;
|
||||
LastTriggerTime = trigtime;
|
||||
LastTrigValid = valid;
|
||||
}
|
||||
|
||||
void
|
||||
SaveLastTrigger(Trigger const *t)
|
||||
{
|
||||
@@ -1382,3 +1394,14 @@ SaveLastTimeTrig(TimeTrig const *t)
|
||||
{
|
||||
memcpy(&LastTimeTrig, t, sizeof(LastTimeTrig));
|
||||
}
|
||||
|
||||
/* Wrapper to ignore warnings about ignoring return value of system() */
|
||||
void
|
||||
System(char const *cmd)
|
||||
{
|
||||
int r;
|
||||
r = system(cmd);
|
||||
if (r == 0) {
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
|
||||
12
src/protos.h
12
src/protos.h
@@ -37,6 +37,7 @@ 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 ParseLiteralTime (char const **s, int *tim);
|
||||
int EvalExpr (char const **e, Value *v, ParsePtr p);
|
||||
int DoCoerce (char type, Value *v);
|
||||
void PrintValue (Value *v, FILE *fp);
|
||||
@@ -89,7 +90,7 @@ 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, TimeTrig *tim, int *err, int save_in_globals);
|
||||
int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals);
|
||||
int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals, int duration_days);
|
||||
int AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals);
|
||||
int ComputeScanStart(int today, Trigger *trig, TimeTrig *tt);
|
||||
char *StrnCpy (char *dest, char const *source, int n);
|
||||
@@ -148,6 +149,15 @@ char const *SynthesizeTag(void);
|
||||
void ClearLastTriggers(void);
|
||||
void SaveLastTrigger(Trigger const *t);
|
||||
void SaveLastTimeTrig(TimeTrig const *t);
|
||||
void SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigtime, int valid);
|
||||
|
||||
void PerIterationInit(void);
|
||||
char const *Decolorize(int r, int g, int b);
|
||||
char const *Colorize(int r, int g, int b);
|
||||
void PrintJSONString(char const *s);
|
||||
void PrintJSONKeyPairInt(char const *name, int val);
|
||||
void PrintJSONKeyPairString(char const *name, char const *val);
|
||||
void PrintJSONKeyPairDate(char const *name, int jul);
|
||||
void PrintJSONKeyPairDateTime(char const *name, int dt);
|
||||
void PrintJSONKeyPairTime(char const *name, int t);
|
||||
void System(char const *cmd);
|
||||
|
||||
75
src/queue.c
75
src/queue.c
@@ -246,11 +246,7 @@ void HandleQueuedReminders(void)
|
||||
|
||||
/* Set up global variables so some functions like trigdate()
|
||||
and trigtime() work correctly */
|
||||
LastTriggerDate = JulianToday;
|
||||
LastTriggerTime = q->tt.ttime;
|
||||
LastTrigValid = 1;
|
||||
SaveLastTrigger(&(q->t));
|
||||
SaveLastTimeTrig(&(q->tt));
|
||||
SaveAllTriggerInfo(&(q->t), &(q->tt), JulianToday, q->tt.ttime, 1);
|
||||
(void) TriggerReminder(&p, &trig, &q->tt, JulianToday);
|
||||
if (Daemon < 0) {
|
||||
printf("NOTE endreminder\n");
|
||||
@@ -452,6 +448,70 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the queue in JSON format */
|
||||
static void
|
||||
json_queue(QueuedRem const *q)
|
||||
{
|
||||
int done = 0;
|
||||
printf("[");
|
||||
while(q) {
|
||||
if (q->tt.nexttime == NO_TIME) {
|
||||
q = q->next;
|
||||
continue;
|
||||
}
|
||||
if (done) {
|
||||
printf(",");
|
||||
}
|
||||
done = 1;
|
||||
printf("{");
|
||||
switch(q->typ) {
|
||||
case NO_TYPE: PrintJSONKeyPairString("type", "NO_TYPE"); break;
|
||||
case MSG_TYPE: PrintJSONKeyPairString("type", "MSG_TYPE"); break;
|
||||
case RUN_TYPE: PrintJSONKeyPairString("type", "RUN_TYPE"); break;
|
||||
case CAL_TYPE: PrintJSONKeyPairString("type", "CAL_TYPE"); break;
|
||||
case SAT_TYPE: PrintJSONKeyPairString("type", "SAT_TYPE"); break;
|
||||
case PS_TYPE: PrintJSONKeyPairString("type", "PS_TYPE"); break;
|
||||
case PSF_TYPE: PrintJSONKeyPairString("type", "PSF_TYPE"); break;
|
||||
case MSF_TYPE: PrintJSONKeyPairString("type", "MSF_TYPE"); break;
|
||||
case PASSTHRU_TYPE: PrintJSONKeyPairString("type", "PASSTHRU_TYPE"); break;
|
||||
default: PrintJSONKeyPairString("type", "?"); break;
|
||||
}
|
||||
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
||||
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
||||
PrintJSONKeyPairTime("ttime", q->tt.ttime);
|
||||
PrintJSONKeyPairTime("nextttime", q->tt.nexttime);
|
||||
PrintJSONKeyPairInt("delta", q->tt.delta);
|
||||
if (q->tt.rep != NO_TIME) {
|
||||
PrintJSONKeyPairInt("rep", q->tt.rep);
|
||||
}
|
||||
if (q->tt.duration != NO_TIME) {
|
||||
PrintJSONKeyPairInt("duration", q->tt.duration);
|
||||
}
|
||||
if (q->passthru[0]) {
|
||||
PrintJSONKeyPairString("passthru", q->passthru);
|
||||
}
|
||||
if (q->sched[0]) {
|
||||
PrintJSONKeyPairString("sched", q->sched);
|
||||
}
|
||||
if (DBufLen(&(q->tags))) {
|
||||
PrintJSONKeyPairString("tags", DBufValue(&(q->tags)));
|
||||
}
|
||||
|
||||
/* Last one is a special case - no trailing comma */
|
||||
printf("\"");
|
||||
PrintJSONString("body");
|
||||
printf("\":\"");
|
||||
if (q->text) {
|
||||
PrintJSONString(q->text);
|
||||
} else {
|
||||
PrintJSONString("");
|
||||
}
|
||||
printf("\"}");
|
||||
q = q->next;
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* DaemonWait */
|
||||
@@ -536,6 +596,11 @@ static void DaemonWait(unsigned int sleeptime)
|
||||
}
|
||||
printf("NOTE endqueue\n");
|
||||
fflush(stdout);
|
||||
} else if (!strcmp(cmdLine, "JSONQUEUE\n")) {
|
||||
printf("NOTE JSONQUEUE\n");
|
||||
json_queue(QueueHead);
|
||||
printf("NOTE ENDJSONQUEUE\n");
|
||||
fflush(stdout);
|
||||
} else if (!strcmp(cmdLine, "REREAD\n")) {
|
||||
printf("NOTE reread\n");
|
||||
fflush(stdout);
|
||||
|
||||
118
src/rem2ps.c
118
src/rem2ps.c
@@ -5,7 +5,7 @@
|
||||
/* Print a PostScript calendar. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2020 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -99,6 +99,7 @@ CalEntry *CurEntries = NULL;
|
||||
CalEntry *PsEntries[32];
|
||||
PageType *CurPage;
|
||||
char PortraitMode;
|
||||
char DaynumRight;
|
||||
char NoSmallCal;
|
||||
char UseISO;
|
||||
|
||||
@@ -140,6 +141,18 @@ void WriteOneEntry (CalEntry *c);
|
||||
void GetSmallLocations (void);
|
||||
char const *EatToken(char const *in, char *out, int maxlen);
|
||||
|
||||
static void
|
||||
put_escaped_string(char const *s)
|
||||
{
|
||||
while(*s) {
|
||||
if (*s == '\\' || *s == '(' || *s == ')') {
|
||||
PutChar('\\');
|
||||
}
|
||||
PutChar(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* StrCmpi */
|
||||
@@ -336,7 +349,7 @@ int main(int argc, char *argv[])
|
||||
!strcmp(DBufValue(&buf), PSBEGIN2)) {
|
||||
if (!validfile) {
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2020 by Dianne Skoll\n\n", VERSION);
|
||||
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2021 by Dianne Skoll\n\n", VERSION);
|
||||
fprintf(stderr, "Generating PostScript calendar\n");
|
||||
}
|
||||
}
|
||||
@@ -587,6 +600,12 @@ void WriteProlog(void)
|
||||
printf("%%%%Pages: (atend)\n");
|
||||
printf("%%%%Orientation: %s\n", PortraitMode ? "Portrait" : "Landscape");
|
||||
printf("%%%%EndComments\n");
|
||||
if (PortraitMode) {
|
||||
printf("<< /PageSize [%d %d] >> setpagedevice\n", x, y);
|
||||
} else {
|
||||
/* They were swapped up above, so swap them back or we'll get rotated output */
|
||||
printf("<< /PageSize [%d %d] >> setpagedevice\n", y, x);
|
||||
}
|
||||
|
||||
for (i=0; PSProlog1[i]; i++) puts(PSProlog1[i]);
|
||||
if (!MondayFirst)
|
||||
@@ -679,7 +698,7 @@ void WriteCalEntry(void)
|
||||
printf("]\n");
|
||||
|
||||
/* Print the day number */
|
||||
printf("(%d)\n", CurDay);
|
||||
printf("(%d) %d\n", CurDay, (int) DaynumRight);
|
||||
/* Do it! */
|
||||
printf("DoCalBox\n");
|
||||
|
||||
@@ -819,6 +838,7 @@ void Init(int argc, char *argv[])
|
||||
FillPage = 0;
|
||||
MondayFirst = 0;
|
||||
SmallLocation = "bt";
|
||||
DaynumRight = 1;
|
||||
|
||||
for(j=0; j<32; j++) PsEntries[i] = NULL;
|
||||
|
||||
@@ -935,6 +955,7 @@ void Init(int argc, char *argv[])
|
||||
|
||||
case 'i': UseISO = 1; break;
|
||||
|
||||
case 'x': DaynumRight = 0; break;
|
||||
case 'c': k=(*s);
|
||||
if (!k) {
|
||||
SmallLocation = SmallCalLoc[0];
|
||||
@@ -979,6 +1000,7 @@ void Usage(char const *s)
|
||||
fprintf(stderr, "-b size Set border size for calendar entries\n");
|
||||
fprintf(stderr, "-t size Set line thickness\n");
|
||||
fprintf(stderr, "-e Make calendar fill entire page\n");
|
||||
fprintf(stderr, "-x Put day numbers on left instead of right\n");
|
||||
fprintf(stderr, "-o[lrtb] marg Specify left, right, top and bottom margins\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1054,10 +1076,10 @@ int DoQueuedPs(void)
|
||||
FILE *fp;
|
||||
int fnoff;
|
||||
char buffer[512];
|
||||
char const *size, *extra;
|
||||
char fbuffer[512];
|
||||
char const *size, *fsize, *extra;
|
||||
char const *s;
|
||||
int num, r, g, b, phase, fontsize, moonsize;
|
||||
unsigned char c;
|
||||
|
||||
if (!MondayFirst) begin = CurDay - WkDayNum;
|
||||
else begin = CurDay - (WkDayNum ? WkDayNum-1 : 6);
|
||||
@@ -1129,19 +1151,28 @@ int DoQueuedPs(void)
|
||||
while(*s && isspace(*s)) {
|
||||
s++;
|
||||
}
|
||||
while(*s) {
|
||||
if (*s == '\\' || *s == '(' || *s == ')') {
|
||||
PutChar('\\');
|
||||
}
|
||||
PutChar(*s);
|
||||
s++;
|
||||
}
|
||||
put_escaped_string(s);
|
||||
printf(") show grestore\n");
|
||||
break;
|
||||
|
||||
case SPECIAL_MOON: /* Moon phase */
|
||||
num = sscanf(e->entry+fnoff, "%d %d %d", &phase, &moonsize,
|
||||
&fontsize);
|
||||
/* 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++;
|
||||
|
||||
if (num == 1) {
|
||||
moonsize = -1;
|
||||
fontsize = -1;
|
||||
@@ -1163,7 +1194,27 @@ int DoQueuedPs(void)
|
||||
size = buffer;
|
||||
}
|
||||
|
||||
printf("gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub\n", size, size);
|
||||
/* Store the starting X coordinate in "moonstartx" */
|
||||
if (DaynumRight) {
|
||||
printf("Border %s add /moonstartx exch def", size);
|
||||
} else {
|
||||
printf("xincr Border sub %s sub ", size);
|
||||
if (*extra) {
|
||||
if (fontsize < 0) {
|
||||
fsize = "EntrySize";
|
||||
} else {
|
||||
sprintf(fbuffer, "%d", fontsize);
|
||||
fsize = fbuffer;
|
||||
}
|
||||
printf("/EntryFont findfont %s scalefont setfont (",
|
||||
fsize);
|
||||
put_escaped_string(extra);
|
||||
printf(") stringwidth pop sub Border sub ");
|
||||
}
|
||||
printf("/moonstartx exch def\n");
|
||||
}
|
||||
printf(" gsave 0 setgray newpath ");
|
||||
printf("moonstartx BoxHeight Border sub %s sub\n", size);
|
||||
printf(" %s 0 360 arc closepath\n", size);
|
||||
switch(phase) {
|
||||
case 0:
|
||||
@@ -1174,49 +1225,28 @@ int DoQueuedPs(void)
|
||||
break;
|
||||
|
||||
case 1:
|
||||
printf("stroke\n");
|
||||
printf("newpath Border %s add BoxHeight Border sub %s sub\n",
|
||||
size, size);
|
||||
printf("stroke\nnewpath ");
|
||||
printf("moonstartx BoxHeight Border sub %s sub\n", 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("stroke\nnewpath ");
|
||||
printf("moonstartx BoxHeight Border sub %s sub\n", 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);
|
||||
printf("moonstartx %s add Border add BoxHeight border sub %s sub %s sub moveto\n", size, size, size);
|
||||
if (fontsize < 0) {
|
||||
size = "EntrySize";
|
||||
fsize = "EntrySize";
|
||||
} else {
|
||||
sprintf(buffer, "%d", fontsize);
|
||||
size = buffer;
|
||||
sprintf(fbuffer, "%d", fontsize);
|
||||
fsize = fbuffer;
|
||||
}
|
||||
printf("/EntryFont findfont %s scalefont setfont (",
|
||||
size);
|
||||
while(*extra) {
|
||||
c = (unsigned char) *extra++;
|
||||
if (c == '\\' || c == '(' || c == ')') PutChar('\\');
|
||||
PutChar(c);
|
||||
}
|
||||
fsize);
|
||||
put_escaped_string(extra);
|
||||
printf(") show\n");
|
||||
|
||||
}
|
||||
|
||||
13
src/rem2ps.h
13
src/rem2ps.h
@@ -5,7 +5,7 @@
|
||||
/* Define the PostScript prologue */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2020 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -13,7 +13,7 @@ char *PSProlog1[] =
|
||||
{
|
||||
"% This file was produced by Remind and Rem2PS, written by",
|
||||
"% Dianne Skoll.",
|
||||
"% Remind and Rem2PS are Copyright 1992-2020 Dianne Skoll.",
|
||||
"% Remind and Rem2PS are Copyright 1992-2021 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",
|
||||
@@ -196,9 +196,10 @@ char *PSProlog2[] =
|
||||
"% Variables for calendar boxes:",
|
||||
"% ytop - current top position",
|
||||
"% ymin - minimum y reached for current row",
|
||||
"% border ytop xleft width textarray daynum DoCalBox ybot",
|
||||
"% border ytop xleft width textarray daynum onright DoCalBox ybot",
|
||||
"% Do the entries for one calendar box. Returns lowest Y-coordinate reached",
|
||||
"/DoCalBox {",
|
||||
" /onright exch def",
|
||||
" /daynum exch def",
|
||||
" /textarr exch def",
|
||||
" /wid exch def",
|
||||
@@ -207,8 +208,10 @@ char *PSProlog2[] =
|
||||
" /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",
|
||||
" onright 1 eq",
|
||||
" {xl wid add border sub daynum stringwidth pop sub yt border sub DaySize sub moveto daynum show}",
|
||||
" {xl border add yt border sub DaySize sub moveto daynum show}",
|
||||
" ifelse",
|
||||
"% 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",
|
||||
|
||||
@@ -150,7 +150,7 @@ void IssueSortedReminders(void)
|
||||
break;
|
||||
|
||||
case RUN_TYPE:
|
||||
system(cur->text);
|
||||
System(cur->text);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
30
src/token.c
30
src/token.c
@@ -67,6 +67,7 @@ Token TokArray[] = {
|
||||
{ "june", 3, T_Month, 5 },
|
||||
{ "march", 3, T_Month, 2 },
|
||||
{ "may", 3, T_Month, 4 },
|
||||
{ "maybe-uncomputable", 5, T_MaybeUncomputable, 0},
|
||||
{ "monday", 3, T_WkDay, 0 },
|
||||
{ "msf", 3, T_RemType, MSF_TYPE },
|
||||
{ "msg", 3, T_RemType, MSG_TYPE },
|
||||
@@ -257,6 +258,7 @@ void FindNumericToken(char const *s, Token *t)
|
||||
{
|
||||
int mult = 1, hour, min;
|
||||
char const *s_orig = s;
|
||||
int ampm = 0;
|
||||
|
||||
t->type = T_Illegal;
|
||||
t->val = 0;
|
||||
@@ -284,10 +286,6 @@ void FindNumericToken(char const *s, Token *t)
|
||||
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;
|
||||
@@ -299,7 +297,29 @@ void FindNumericToken(char const *s, Token *t)
|
||||
s++;
|
||||
hour = t->val;
|
||||
PARSENUM(min, s);
|
||||
if (*s || min > 59) return; /* Illegal time */
|
||||
if (min > 59) return; /* Illegal time */
|
||||
/* Check for p[m] or a[m] */
|
||||
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
|
||||
ampm = tolower(*s);
|
||||
s++;
|
||||
if (*s == 'm' || *s == 'M') {
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if (*s) return; /* Illegal time */
|
||||
if (ampm) {
|
||||
if (hour < 1 || hour > 12) return;
|
||||
if (ampm == 'a') {
|
||||
if (hour == 12) {
|
||||
hour = 0;
|
||||
}
|
||||
} else if (ampm == 'p') {
|
||||
if (hour < 12) {
|
||||
hour += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t->val = hour*60 + min; /* Convert to minutes past midnight */
|
||||
if (hour <= 23) {
|
||||
t->type = T_Time;
|
||||
|
||||
@@ -454,11 +454,7 @@ AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int sav
|
||||
|
||||
}
|
||||
if (save_in_globals) {
|
||||
LastTriggerTime = tim->ttime;
|
||||
SaveLastTimeTrig(tim);
|
||||
SaveLastTrigger(trig);
|
||||
LastTriggerDate = r;
|
||||
LastTrigValid = 1;
|
||||
SaveAllTriggerInfo(trig, tim, r, tim->ttime, 1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -474,10 +470,29 @@ AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int sav
|
||||
int ComputeTrigger(int today, Trigger *trig, TimeTrig *tim,
|
||||
int *err, int save_in_globals)
|
||||
{
|
||||
int r = ComputeTriggerNoAdjustDuration(today, trig, tim, err, save_in_globals);
|
||||
int r = ComputeTriggerNoAdjustDuration(today, trig, tim, err, save_in_globals, 0);
|
||||
if (*err != OK) {
|
||||
return r;
|
||||
}
|
||||
if (r == today) {
|
||||
if (tim->ttime != NO_TIME) {
|
||||
trig->eventstart = MINUTES_PER_DAY * r + tim->ttime;
|
||||
if (tim->duration != NO_TIME) {
|
||||
trig->eventduration = tim->duration;
|
||||
}
|
||||
}
|
||||
if (save_in_globals) {
|
||||
SaveAllTriggerInfo(trig, tim, r, tim->ttime, 1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if (trig->duration_days) {
|
||||
r = ComputeTriggerNoAdjustDuration(today, trig, tim, err, save_in_globals, trig->duration_days);
|
||||
if (*err != OK) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
r = AdjustTriggerForDuration(today, r, trig, tim, save_in_globals);
|
||||
return r;
|
||||
}
|
||||
@@ -491,10 +506,10 @@ int ComputeTrigger(int today, Trigger *trig, TimeTrig *tim,
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
||||
int *err, int save_in_globals)
|
||||
int *err, int save_in_globals, int duration_days)
|
||||
{
|
||||
int nattempts = 0,
|
||||
start = today - trig->duration_days,
|
||||
start = today - duration_days,
|
||||
nextstart = 0,
|
||||
y, m, d, omit,
|
||||
result;
|
||||
@@ -561,7 +576,7 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
||||
}
|
||||
|
||||
/** FIXME: Fix bad interaction with SATISFY... need to rethink!!! */
|
||||
if (result+trig->duration_days >= today &&
|
||||
if (result+duration_days >= today &&
|
||||
(trig->skip != SKIP_SKIP || !omit)) {
|
||||
if (save_in_globals) {
|
||||
LastTriggerDate = result; /* Save in global var */
|
||||
|
||||
@@ -73,6 +73,7 @@ typedef struct {
|
||||
int duration_days; /* Duration converted to days to search */
|
||||
int eventstart; /* Original event start (datetime) */
|
||||
int eventduration; /* Original event duration (minutes) */
|
||||
int maybe_uncomputable; /* Suppress "can't compute trigger" warnings */
|
||||
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
|
||||
char warn[VAR_NAME_LEN+1]; /* Warning function */
|
||||
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
|
||||
@@ -171,7 +172,8 @@ enum TokTypes
|
||||
T_Duration,
|
||||
T_LongTime,
|
||||
T_OmitFunc,
|
||||
T_Through
|
||||
T_Through,
|
||||
T_MaybeUncomputable
|
||||
};
|
||||
|
||||
/* The structure of a token */
|
||||
|
||||
23
src/utils.c
23
src/utils.c
@@ -123,3 +123,26 @@ int DateOK(int y, int m, int d)
|
||||
d > DaysInMonth(m, y) ) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
/* Functions designed to defeat gcc optimizer */
|
||||
|
||||
int _private_div(int a, int b) { return a/b; }
|
||||
int _private_add_overflow(int result, int b, int old)
|
||||
{
|
||||
if (b > 0 && result < old) return 1;
|
||||
if (b < 0 && result > old) return 1;
|
||||
return 0;
|
||||
}
|
||||
int _private_sub_overflow(int result, int b, int old)
|
||||
{
|
||||
if (b < 0 && result < old) return 1;
|
||||
if (b > 0 && result > old) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _private_unminus_overflow(int a, int b)
|
||||
{
|
||||
if (a > 0 && b > 0) return 1;
|
||||
if (a < 0 && b < 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
20
src/var.c
20
src/var.c
@@ -17,6 +17,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "types.h"
|
||||
#include "expr.h"
|
||||
#include "globals.h"
|
||||
@@ -31,6 +32,9 @@
|
||||
#define VALUE ErrMsg[E_VAL]
|
||||
#define UNDEF ErrMsg[E_UNDEF]
|
||||
|
||||
static int IntMin = INT_MIN;
|
||||
static int IntMax = INT_MAX;
|
||||
|
||||
static Var *VHashTbl[VAR_HASH_SIZE];
|
||||
|
||||
typedef int (*SysVarFunc)(int, Value *);
|
||||
@@ -475,17 +479,17 @@ int DoDump(ParsePtr p)
|
||||
DumpVarTable();
|
||||
return OK;
|
||||
}
|
||||
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
|
||||
fprintf(ErrFp, "%s %s\n\n", 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,
|
||||
if (!v) fprintf(ErrFp, "%s %s\n",
|
||||
DBufValue(&buf), UNDEF);
|
||||
else {
|
||||
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
|
||||
fprintf(ErrFp, "%s ", v->name);
|
||||
PrintValue(&(v->v), ErrFp);
|
||||
fprintf(ErrFp, "\n");
|
||||
}
|
||||
@@ -513,12 +517,12 @@ void DumpVarTable(void)
|
||||
register Var *v;
|
||||
register int i;
|
||||
|
||||
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
|
||||
fprintf(ErrFp, "%s %s\n\n", VARIABLE, VALUE);
|
||||
|
||||
for (i=0; i<VAR_HASH_SIZE; i++) {
|
||||
v = VHashTbl[i];
|
||||
while(v) {
|
||||
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
|
||||
fprintf(ErrFp, "%s ", v->name);
|
||||
PrintValue(&(v->v), ErrFp);
|
||||
fprintf(ErrFp, "\n");
|
||||
v = v->next;
|
||||
@@ -657,10 +661,12 @@ static SysVar SysVarArr[] = {
|
||||
{"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 },
|
||||
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 500 },
|
||||
{"HushMode", 0, INT_TYPE, &Hush, 0, 0 },
|
||||
{"IgnoreOnce", 0, INT_TYPE, &IgnoreOnce, 0, 0 },
|
||||
{"InfDelta", 0, INT_TYPE, &InfiniteDelta, 0, 0 },
|
||||
{"IntMax", 0, INT_TYPE, &IntMax, 0, 0 },
|
||||
{"IntMin", 0, INT_TYPE, &IntMin, 0, 0 },
|
||||
{"LatDeg", 1, INT_TYPE, &LatDeg, -90, 90 },
|
||||
{"LatMin", 1, INT_TYPE, &LatMin, -59, 59 },
|
||||
{"LatSec", 1, INT_TYPE, &LatSec, -59, 59 },
|
||||
@@ -835,7 +841,7 @@ static void DumpSysVar(char const *name, const SysVar *v)
|
||||
return;
|
||||
}
|
||||
if (name) strcat(buffer, name); else strcat(buffer, v->name);
|
||||
fprintf(ErrFp, "%*s ", VAR_NAME_LEN+1, buffer);
|
||||
fprintf(ErrFp, "%16s ", buffer);
|
||||
if (v) {
|
||||
if (v->type == SPECIAL_TYPE) {
|
||||
Value val;
|
||||
|
||||
@@ -3,6 +3,6 @@ cd /home/dfs/Software/Remind.git || exit 1
|
||||
|
||||
rm -f .git/COMMIT_EDITMSG .git/*~
|
||||
|
||||
git update-server-info && cd .git && rsync --archive --verbose --progress --delete ./ dianne.skoll.ca:web/projects/remind/git/Remind.git/
|
||||
git update-server-info && cd .git && rsync --exclude HEADER.html --archive --verbose --progress --delete ./ dianne.skoll.ca:web/projects/remind/git/Remind.git/
|
||||
exit $?
|
||||
|
||||
|
||||
@@ -289,6 +289,18 @@ rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
|
||||
# If we're already in a utf-8 locale, do
|
||||
# nothing
|
||||
|
||||
if ! echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
|
||||
export LC_ALL=en_US.utf-8
|
||||
fi
|
||||
|
||||
if ! echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
|
||||
export LANG=en_US.utf-8
|
||||
fi
|
||||
|
||||
../src/remind -w128 -c ../tests/utf-8.rem 1 Nov 2019 >> ../tests/test.out
|
||||
cmp -s ../tests/test.out ../tests/test.cmp
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "Remind: Acceptance test PASSED"
|
||||
|
||||
2298
tests/test.cmp
2298
tests/test.cmp
File diff suppressed because it is too large
Load Diff
161
tests/test.rem
161
tests/test.rem
@@ -337,7 +337,7 @@ set a103 trigtimedelta()
|
||||
set a104 trigtimerep()
|
||||
set a105 trigduration()
|
||||
|
||||
REM 2010-09-03 +3 -4 UNTIL 2012-01-01 PRIORITY 7 *14 AT 14:41 +15 *2 DURATION 3:33 MSG foo
|
||||
REM 2010-09-03 +3 -4 UNTIL 2012-01-01 PRIORITY 7 *14 AT 14:41 +15 *2 DURATION 213 MSG foo
|
||||
set a106 trigback()
|
||||
set a107 trigdelta()
|
||||
set a108 trigrep()
|
||||
@@ -376,6 +376,14 @@ set a133 trigduration()
|
||||
set a134 trigeventstart()
|
||||
set a135 trigeventduration()
|
||||
|
||||
# These will issue errors
|
||||
REM Mon OMIT Mon SKIP MSG Never ever ever...
|
||||
REM Mon SATISFY [wkdaynum($T) == 3] MSG Nope nope...
|
||||
|
||||
# These will just silently not trigger
|
||||
REM MAYBE-UNCOMPUTABLE Mon OMIT Mon SKIP MSG Never ever ever...
|
||||
REM MAYBE-UNCOMPUTABLE Mon SATISFY [wkdaynum($T) == 3] MSG Nope nope...
|
||||
|
||||
dump
|
||||
dump $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
OMIT 2010-09-03 THROUGH 2010-09-15
|
||||
@@ -386,6 +394,9 @@ OMIT DUMP
|
||||
# Regression test for bugfix in Hebrew calendar Adar jahrzeit
|
||||
[_i(14, "Adar", today(), 5761)] MSG Purim
|
||||
|
||||
# Regression test for bug found by Larry Hynes
|
||||
REM SATISFY [day(trigdate()-25) == 14] MSG Foo
|
||||
|
||||
# Check combo of SATISFY and long-duration events
|
||||
REM 14 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
REM 14 AT 16:00 DURATION 8:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
@@ -397,6 +408,154 @@ REM 14 AT 16:00 DURATION 40:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
# This is now an error
|
||||
REM DURATION 15:00 MSG Should fail... need AT if you have DURATION.
|
||||
|
||||
# Parsing of AM/PM times
|
||||
REM AT 0:00am MSG foo 0a
|
||||
REM AT 1:00AM MSG foo 1a
|
||||
REM AT 2:00am MSG foo 2a
|
||||
REM AT 3:00AM MSG foo 3a
|
||||
REM AT 4:00am MSG foo 4a
|
||||
REM AT 5:00AM MSG foo 5a
|
||||
REM AT 6:00am MSG foo 6a
|
||||
REM AT 7:00AM MSG foo 7a
|
||||
REM AT 8:00am MSG foo 8a
|
||||
REM AT 9:00AM MSG foo 9a
|
||||
REM AT 10:00am MSG foo 10a
|
||||
REM AT 11:00AM MSG foo 11a
|
||||
REM AT 12:00am MSG foo 12a
|
||||
REM AT 13:00AM MSG foo 13a
|
||||
REM AT 0:00pm MSG foo 0p
|
||||
REM AT 1:00PM MSG foo 1p
|
||||
REM AT 2:00pm MSG foo 2p
|
||||
REM AT 3:00PM MSG foo 3p
|
||||
REM AT 4:00pm MSG foo 4p
|
||||
REM AT 5:00PM MSG foo 5p
|
||||
REM AT 6:00pm MSG foo 6p
|
||||
REM AT 7:00PM MSG foo 7p
|
||||
REM AT 8:00pm MSG foo 8p
|
||||
REM AT 9:00PM MSG foo 9p
|
||||
REM AT 10:00pm MSG foo 10p
|
||||
REM AT 11:00PM MSG foo 11p
|
||||
REM AT 12:00pm MSG foo 12p
|
||||
REM AT 13:00PM MSG foo 13p
|
||||
|
||||
DEBUG +x
|
||||
SET x 0:00am + 0
|
||||
SET x 1:00AM + 0
|
||||
SET x 2:00am + 0
|
||||
SET x 3:00AM + 0
|
||||
SET x 4:00am + 0
|
||||
SET x 5:00AM + 0
|
||||
SET x 6:00am + 0
|
||||
SET x 7:00AM + 0
|
||||
SET x 8:00am + 0
|
||||
SET x 9:00AM + 0
|
||||
SET x 10:00am + 0
|
||||
SET x 11:00AM + 0
|
||||
SET x 12:00am + 0
|
||||
SET x 13:00AM + 0
|
||||
|
||||
SET x 0:00pm + 0
|
||||
SET x 1:00PM + 0
|
||||
SET x 2:00pm + 0
|
||||
SET x 3:00PM + 0
|
||||
SET x 4:00pm + 0
|
||||
SET x 5:00PM + 0
|
||||
SET x 6:00pm + 0
|
||||
SET x 7:00PM + 0
|
||||
SET x 8:00pm + 0
|
||||
SET x 9:00PM + 0
|
||||
SET x 10:00pm + 0
|
||||
SET x 11:00PM + 0
|
||||
SET x 12:00pm + 0
|
||||
SET x 13:00PM + 0
|
||||
|
||||
SET x '2015-02-03@0:00am' + 0
|
||||
SET x '2015-02-03@1:00AM' + 0
|
||||
SET x '2015-02-03@2:00am' + 0
|
||||
SET x '2015-02-03@3:00AM' + 0
|
||||
SET x '2015-02-03@4:00am' + 0
|
||||
SET x '2015-02-03@5:00AM' + 0
|
||||
SET x '2015-02-03@6:00am' + 0
|
||||
SET x '2015-02-03@7:00AM' + 0
|
||||
SET x '2015-02-03@8:00am' + 0
|
||||
SET x '2015-02-03@9:00AM' + 0
|
||||
SET x '2015-02-03@10:00am' + 0
|
||||
SET x '2015-02-03@11:00AM' + 0
|
||||
SET x '2015-02-03@12:00am' + 0
|
||||
SET x '2015-02-03@13:00AM' + 0
|
||||
|
||||
SET x '2015-02-03@0:00pm' + 0
|
||||
SET x '2015-02-03@1:00PM' + 0
|
||||
SET x '2015-02-03@2:00pm' + 0
|
||||
SET x '2015-02-03@3:00PM' + 0
|
||||
SET x '2015-02-03@4:00pm' + 0
|
||||
SET x '2015-02-03@5:00PM' + 0
|
||||
SET x '2015-02-03@6:00pm' + 0
|
||||
SET x '2015-02-03@7:00PM' + 0
|
||||
SET x '2015-02-03@8:00pm' + 0
|
||||
SET x '2015-02-03@9:00PM' + 0
|
||||
SET x '2015-02-03@10:00pm' + 0
|
||||
SET x '2015-02-03@11:00PM' + 0
|
||||
SET x '2015-02-03@12:00pm' + 0
|
||||
SET x '2015-02-03@13:00PM' + 0
|
||||
|
||||
# Test the ampm function
|
||||
set x ampm(0:12) + ""
|
||||
set x ampm(1:12) + ""
|
||||
set x ampm(2:12) + ""
|
||||
set x ampm(3:12) + ""
|
||||
set x ampm(4:12) + ""
|
||||
set x ampm(5:12) + ""
|
||||
set x ampm(6:12) + ""
|
||||
set x ampm(7:12) + ""
|
||||
set x ampm(8:12) + ""
|
||||
set x ampm(9:12) + ""
|
||||
set x ampm(10:12) + ""
|
||||
set x ampm(11:12) + ""
|
||||
set x ampm(12:12) + ""
|
||||
set x ampm(13:12) + ""
|
||||
set x ampm(14:12) + ""
|
||||
set x ampm(15:12) + ""
|
||||
set x ampm(16:12) + ""
|
||||
set x ampm(17:12) + ""
|
||||
set x ampm(18:12) + ""
|
||||
set x ampm(19:12) + ""
|
||||
set x ampm(20:12) + ""
|
||||
set x ampm(21:12) + ""
|
||||
set x ampm(22:12) + ""
|
||||
set x ampm(23:12) + ""
|
||||
|
||||
# Coerce with am/pm
|
||||
set x coerce("TIME", "12:45am")
|
||||
set x coerce("TIME", "12:45")
|
||||
set x coerce("TIME", "1:45pm")
|
||||
set x coerce("DATETIME", "2020-05-05@12:45am")
|
||||
set x coerce("DATETIME", "2020-05-05@12:45")
|
||||
set x coerce("DATETIME", "2020-05-05@1:45pm")
|
||||
|
||||
# Overflow - these tests only work on machines with 32-bit
|
||||
# twos-complement signed integers. You may get test failures on
|
||||
# machines with different architectures.
|
||||
set a $IntMin - 1
|
||||
set a $IntMin - $IntMax
|
||||
set a $IntMax - $IntMin
|
||||
set a $IntMax - (-1)
|
||||
set a $IntMax + 1
|
||||
set a $IntMax + $IntMax
|
||||
set a $IntMin + (-1)
|
||||
set a $IntMin + $IntMin
|
||||
set a $IntMax * 2
|
||||
set a $IntMax * $IntMax
|
||||
set a $IntMax * $IntMin
|
||||
set a $IntMin * 2
|
||||
set a $IntMin * $IntMin
|
||||
set a $IntMin * $IntMax
|
||||
set a $IntMin / (-1)
|
||||
set a abs($IntMin)
|
||||
|
||||
# Don't want Remind to queue reminders
|
||||
EXIT
|
||||
|
||||
__EOF__
|
||||
REM This line should not even be seen
|
||||
And you can put whatever you like here.
|
||||
|
||||
4
tests/utf-8.rem
Normal file
4
tests/utf-8.rem
Normal file
@@ -0,0 +1,4 @@
|
||||
MSG ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский
|
||||
MSG עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית
|
||||
|
||||
Wed MSG With tabs and spaces
|
||||
Reference in New Issue
Block a user