summaryrefslogtreecommitdiff
path: root/ipl/progs/daystil.icn
blob: 848542cfa33d59f32b2c9f7b50bf62244909723d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
############################################################################
#
#	File:     daystil.icn
#
#	Subject:  Program to calculate the number of days until a given date
#
#	Author:   Nevin Liber
#
#	Date:     June 29, 1994
#
###########################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#   Usage:    daystil sMonth iDay
#
#   Returns:
#       0   number of days written on &output
#       1   Usage message on &errout (bad parameters)
#
#   Revision History:
#       <1> njl  6/29/94 9:50 PM        First written
#
#   This program calculates the number of days between the current date
#   and the date specified on the command line, and writes this number to
#   &output.  This is useful if you want to know how many days it is
#   until a birthday, wedding day, etc.
#
#   The date on the command line can be specified in a variety of ways.
#   For instance, if you wanted to know how many days it is until
#   August 12 (my birthday), you could specify it as "August 12", "Aug 12",
#   "12 August", or "12 aUGuS", among others.  The match is case
#   insensitive, and the arguments will be accepted as long as exactly
#   one of them is an integer, and if there are exactly two arguments.
#
###########################################################################
#
#   NumberOfDays(sMonth, iDay, iYear) : iNumberOfDays
#
#   NumberOfDays() returns the number of days into iYear that sMonth/iDay
#   occurs.  For instance, NumberOfDays("February", 28) returns 59, since
#   it is the 59th day into any year.  Leap years from 1901 until 2099
#   are taken into account.  It fails if any parameters are bad.
#
#   Defaults:
#       sMonth  current month
#       iDay    current day of the current month
#       iYear   current year
#
############################################################################

procedure NumberOfDays(sMonth, iDay, iYear)

	static	LMonths
	static	LDays
	static	sThisMonth
	static	iThisDay
	static	iThisYear
	local	iDays
	local	i

	initial {	
		LMonths := [
			"january",
			"february",
			"march",
			"april",
			"may",
			"june",
			"july",
			"august",
			"september",
			"october",
			"november",
			"december"
		]

		LDays := [
			31,
			28,
			31,
			30,
			31,
			30,
			31,
			31,
			30,
			31,
			30
		]

		&dateline ? {
			&pos := find(" ") + 1
			sThisMonth := tab(find(" "))
			&pos +:= 1
			iThisDay := integer(tab(find(",")))
			&pos +:= 2
			iThisYear := integer(move(4))
		}
	}

	/sMonth := sThisMonth
	/iDay := iThisDay
	/iYear := iThisYear

	sMonth := string(sMonth) | fail
	iDay := integer(iDay) | fail
	iYear := integer(iYear) | fail

	if 0 ~= iYear % 4 then {
		LDays[2] := 28
	} else {
		LDays[2] := 29
	}

	iDays := iDay
	every i := 1 to *LMonths do {
		if CaselessMatch(sMonth, LMonths[i]) then {
			return iDays
		}
		iDays +:= LDays[i]
	}

end


############################################################################
#
#   CaselessMatch(s1, s2, i1, i2) : i3  caseless match of initial string
#
#	CaselessMatch(s1, s2, i1, i2) produces i1 + *s1 if
#   map(s1) == map(s2[i1+:*s1]) but fails otherwise.
#
#   This is the same as the built-in function match(), except the
#   comparisons are done without regard to case.
#
#   Defaults:
#       s2      &subject
#       i1      &pos if s2 is defaulted, otherwise 1
#       i2      0
#
#   Errors:
#       101     i1 or i2 not integer
#       103     s1 or s2 not string
#
############################################################################

procedure CaselessMatch(s1, s2, i1, i2)

	s1 := map(string(s1))
	/i1 := (/s2 & &pos)
	s2 := map(string(s2) | (/s2 & &subject))

	return match(s1, s2, i1, i2)
	

end


############################################################################
#
#   Usage(fErrout, iStatus)     write usage message to fErrout and exit
#
#   Usage(fErrout, iStatus) writes the usage message to file fErrout
#   and exits with exit status code iStatus
#
#   Defaults:
#       fErrout  &errout
#       iStatus  1
#
############################################################################

procedure Usage(fErrout, iStatus)

	/fErrout := &errout
	iStatus := (integer(iStatus) | 1)

	write(fErrout, "Usage: DaysTil sMonth iDay")
	exit(iStatus)

end


############################################################################
#
#   main(LArguments)
#
#	main(LArguments) checks to make sure there are two arguments, exactly
#   one of which is an integer.  If so, it tries to calculate the number
#   of days between the current date and the date specified, taking into
#   account if the specified date occurs after today's date only in the
#   following year.  On a parameter error, it writes the usage message
#   to &errout and exits with status 1.  Otherwise, it writes the number
#   of days to &output and exits with status 0.
#
############################################################################

procedure main(LArguments)

	local	sArgument
	local	sMonth
	local	iDay
	local	iToday
	local	iNumberOfDays


	if 2 ~= *LArguments then {
		Usage()
	}

	every sArgument := !LArguments do {
		(iDay := integer(sArgument)) | (sMonth := sArgument)
	}

	if /iDay | /sMonth then {
		Usage()
	}
	
	iToday := NumberOfDays()
	iNumberOfDays := NumberOfDays(sMonth, iDay) | Usage()
	if iNumberOfDays < iToday then {
		iNumberOfDays := NumberOfDays("december", 31) + NumberOfDays(sMonth, iDay, integer(&date[1+:4]) + 1)
	}
	
	write(iNumberOfDays - iToday)

end