Contents of the POP-CAL.DOC file
A Calendar for all Seasons
(PC Magazine Vol 5 No 17 October 14, 1986 by Leo Forrest)
POP-CAL is a memory-resident pop-up calendar. It displays compact
monthly calendars in a small window on your screen without biting off a
big chunk of memory. POP-CAL supplies accurate calendars back to the
start of the Gregorian calendar, which is 1583.
When loading POP-CAL notes the current month and year, then
displays a calendar for that month in the current year when it first
pops up. After that, you may move to new months and/or years by
pressing the four cursor control keys on the numeric keypad. The
left arrow key takes you back a month, and when you pass January,
the year is decreased by one and the month is reset to December.
Similarly, the right arrow key increments months and resets to
January of the next year when you pass December.
The up arrow and down arrow keys control the years directly; if
you try to go back before 1583, the down arrow key is ignored. All
keystrokes, except the four cursor keys and the Alt-C keys, are
ignored while the calendar window is on the screen. This includes
all the numbers on the numeric keypad, so make sure that the NumLock
key is not on if the calendar fails to respond to the cursor keys.
POP-CAL will run just as fast as you can send the cursor
keystrokes, but that is only about a decade per second at standard
keyboard settings. (You can run through about a century every 4
seconds if you have one of the high-speed typematic utilities
installed.) For convenience, especially when pursuing distant dates,
POP-CAL starts with the current month only upon the initial call.
After that, the first calendar popped up will be the last one
examined earlier in the session.
The Alt-C key combination was chosen for purely mnemonic reasons.
Other programs you use may already require this key pair, or you might
yourself already be using it to call one of your 1-2-3 keyboard macros.
In such a case, it's easy enough to modify POP-CAL to use another
letter or combination of letters.
If you're working with the POP-CAL.ASM listing and want to use a
new trigger key, alter the "scan_code" value, which is currently set
at 2E00h. If you are working with POP-CAL.BAS, you will want to
change the fifth number on line 430 (currently 46), along with the
row total for that line (the last number on the line) and the grand
total checksum on line 270.
A handy source for some possible key combinations may be found
in the IBM BASIC manual. From its Extended Codes table you can see,
for example, that Alt-D has a second code of 32. This could be used
in place of the 46 on line 430 to convert the trigger from Alt-C to
Alt-D. Scanning further down the page, you'll see that replacing the
46 with 119 would convert the Alt-C to Ctrl-Home.
When altering the 46 on line 430 of POP-CAL.BAS, you must also
change the 772 at the end of the line and teh 96431 on line 270. For
instance, if you are converting to Alt-D, substitute 32 for the 46.
Then change 772 to (772 - 46 + 32), i.e., to 758, so that the row
adds up properly. Similarly, change the 96431 on line 270 to 96417
(96413 - 46 + 32) so that the last number of all the data lines will
still add up to the right checksum.
Alternatively, once you've created POP-CAL.COM, you can use
DEBUG to alter the trigger by changing the byte at address 174.
The Gregorian calendar is only slightly more difficult to
generate than the Julian if time is restricted to after 1582. Since
there are 365 days per non-leap year and only 364 days in 52 weeks,
the first day of the year advances one weekday per year. Thus, since
January 1, 1583 was a Saturday, January 1, 1584 was a Sunday, etc.
Further, since leap years have an extra day, the weekday of the first
of each year following any leap year must advance 2 days. Hence, the
first day of any year after 1583 can be calculated by adding the
number of years since 1583 to the weekday of January 1, 1583, and
then adding in an extra day for each leap year. The resultant sum,
when divided by 7, yields the weekday of the start of any year, where
Sunday produces a remainder of 0 and Saturday has a remainder of 6.
The only twist in the above logic is that Pope Gregory declared
that all centennial years would not be leap years unless they were
evenly divisible by 400. Thus, 1900 was not a leap year but 2000
will be. This is handled in the code by calculating the number of
intervening centuries, subtracting this number from the sum above,
and then adding back 1 day for each 400 years.
Once you have calculated the first day of the year, finding the
first day of the month requires only that you know the number of days
in each preceding month. You then add the days between the first of
the year and the first day of the subject month to the sum from above
and divide this total by 7. A remainder of 0 means the month begins
on Sunday, etc.
Essentially there are three faily common techniques used to
activate pop-up routines: checking the keyboard flags once each half-
second or so, intercepting the keystroke interrupts when keys are
struck, and intercepting keys as they are passed to requesting
programs. The third of these methods is the simplest and is adequate
for routines that are not time-critical.
POP-CAL, when loading, substitutes the address of its INT 16h
routine for that previously found in the system interrupt table located
at the bottom of memory. This substitute routine allows POP-CAL to
monitor each request from a user program (including DOS) for a new key
from the keyboard buffer. By examining the returned key first, POP-CAL
can then decide whether to use the key itself or pass it along to the
Interrupt 16h has two standard read functions. If AH=0, this
BIOS read routine simply begisn looping and waits for a key to become
available in the keyboard buffer. As soon as one is typed in at the
keyboard, the routine removes the key from the buffer and returns it
to the caller in the AX register. However, if AH=1, the BIOS routine
reads ahead in the buffer, returning the next key (if it exists) in
AX without removing it from the buffer. The user program then decides
whether or not AX has a valid key by checking the setting of the empty
buffer (zero) flag.
Some commercial desktop programs monitor both the "read-ahead"
and the "wait-for-key" calls to Interrupt 16h. While this may result
in a quicker response if the calling program is operating in the read-
ahead mode and if no intervening characters already exist in the
keyboard buffer, it also requires about 40 additional bytes of code
and is not reliable enough for use in truly time-critical routines,
such as might be used for controlling the output to a printer.
Since monitoring the read-ahead function yields only spotty and
unreliable improvement in response time, POP-CAL checks the results of
only the wait-for-key calls. Meanwhile the read-ahead calls, like the
keyboard status calls, are simply ignored and are passed along for
processing without further ado.
When a user program issues a wait-for-key call, POP-CAL pushes
the processor flags onto the stack and calls the old key-reading
routine that it has replaced. This forces the old routine to return
to POP-CAL instead of to the caller routine when done and allows
POP-CAL to decide what to do next.
When control is returned to POP-CAL, the program first checks
the new key in AX against its 2-byte trigger key code. If both bytes
in AX match the stored trigger key, all the caller's registers are
saved and the calendar function begins. Otherwise, the key is simply
passed along to the caller and POP-CAL relaxes until the next call for
Although it's not essential, POP-CAL uses a 2-byte trigger key
to give the user the widest possible choice of trigger keys consistent
with simplicity. To generate an even wider choice, the next logical
step would be to begin requiring a triple-key combination to be
pressed before triggering, such as pressing the Alt key in concert
with, say the left shift key and some standard letter. This is fairly
easy to implement, requiring only that the BIOS shift keys be tested,
along with the value returned in AX from the Alt and third key.
In order to return control to the calling program successfully
after calendar processing has been completed, POP-CAL must ensure that
the caller's stack and all of the caller's registers (except AX) are
exactly as they were when POP-CAL took control. To do this, it needs
to save the registers in some easily accessible location. While
normally this is done by "pushing" them onto the current stack,
POP-CAL has no way of knowing whether or not there is room for them.
If the stack overflows, it will probably trash code or important data,
causing the calling program to go into a tailspin.
To avoid potential overflow problems, POP-CAL switches the stack
to an area in its own program prefix area, which has ample room. To
do so, the caller's stack segment address and pointer are first saved
within POP-CAL's program prefix area. The stack segment is then
changed to POP-CAL's own code segment, and the stack pointer is reset
so that the next "push" will begin storing data immediately below the
ROM 16h variable in the PPF.
Solving the overflow problem unfortunately also generates a brand
new hazard. Suppose POP-CAL has seen an Alt-C, saved the caller's
registers, and is now waiting for a cursor key to be pressed. Without
some sort of flag telling it not to, the next Alt-C seen would cause
POP-CAl to start saving the "caller's" registers all over again. In
this case, however, the caller would end up saving its own registers
on top of those saved for returning to the original caller.
To protect POP-CAL's stack from itself, the BUSY flag is
introduced. It is set as soon as the first Alt-C is seen and stays
on until the calendar work is done and all of the caller's registers
Once POP-CAL has set its BUSY flag and saved the caller's
registers, it next must clear away an area of the screen for displaying
its calendars. Of course, since the user will presumably wish to
continue with his work after this excursion into date checking and
calendar generation, POP-CAl must save the user's original screen data
as well. Then when returning from making calendars, POP-CAL can
restore the screen as though nothing had happened.
While BIOS routines are available for reading data from the
screen, as well as writing data on the screen, these are quite slow.
So, although they have the advantage of working under all video modes,
POP-CAL ignores them in favor of direct buffer update techniques. To
conserve code, however, only standard monochrome and color (and EGA)
text modes are actually handled properly. Hence, while POP-CAL will
run in graphics modes and will save and restore the screen, the
display is useless in graphics.
Alt-CToggles calendar on/off
Right-ArrowAhead one month
Left-ArrowBack one month
Up-ArrowAhead one year
Down-ArrowBack one year