|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 6869 (0x1ad5)
Types: TextFile
Notes: UNIX file
Names: »cal.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/cal.c«
/*
* Print calendar for specified year (and month).
* Allows month to be numeric or alphabetic.
*/
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#define GREGYEAR 1752 /* Year of start of Gregorian calendar */
#define GREGMON SEP /* Month of above */
#define GREGDAY 3 /* day of month of changeover */
#define GREGADJ 11 /* Adjustment of cal. (days) for Gregorian */
/* The calendar skipped 11 days after
* September 3, 1752 in England.
* That made the date jump 12 days
* forward rather than the usual 1.
* The original Gregorian reform was in
* 1582, at which time only 10 days were
* suppressed. France and Russia adopted
* the Gregorian calendar after 1752.
* My calculations, which don't make
* complete sense, suggest that the
* corrections would be:
* 12 days after 1800
* 13 days after 1900
* and 14 days after 2100
* because the Gregorian calendar skips
* leap years which fall on century years
* unless they are quadracents and not
* 4000 AD.
*/
#define TMYBIAS 1900 /* bias of year field in struct tm */
char *mnames[] = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
/*
* Days per month array (non-leap).
* January is at dpm[1].
*/
char dpm[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char dayhead[] = " Su Mo Tu We Th Fr Sa";
#define DAYWIDTH (sizeof dayhead -1)
#define GAP 5 /* Gap between months */
#define CENTRE ((3*DAYWIDTH+2*GAP)/2+2) /* Centred 4 digit year pos. */
#define MPL 3 /* Months per line */
#define JAN 1
#define FEB 2
#define MAR 3
#define APR 4
#define MAY 5
#define JUN 6
#define JUL 7
#define AUG 8
#define SEP 9
#define OCT 10
#define NOV 11
#define DEC 12
char caldays[MPL][6][7], /* 3 per line, 6 lines, 7 days */
outbuf[BUFSIZ]; /* stdout setbuf */
int baseday; /* Weekday of current year's Jan. 1 */
main(argc, argv)
register char *argv[];
{
int month;
unsigned year;
struct tm *now;
long intime;
long time();
setbuf(stdout, outbuf);
intime = time(NULL);
now = localtime(&intime);
month = 0;
year = now->tm_year + TMYBIAS;
++argv;
switch (argc) {
case 1:
month = now->tm_mon + 1;
break;
case 2:
if (isdigit(**argv))
year = atoi(*argv);
else
month = getmon(*argv);
break;
case 3:
if (!isdigit(*argv[0]))
month = getmon(*argv++);
else if (isdigit(*argv[1])) {
month = atoi(*argv++);
if (month == 0)
month = -1;
} else
month = getmon(argv[1]);
year = atoi(*argv);
break;
default:
usage();
}
if (month < 0 || month > 12 || year <= 0 || year > 9999)
usage();
cal(year, month);
}
/*
* Produce a calendar for the specifed year and month.
* (If month is zero, then do whole year.)
* Setup baseday for fillcal to speed it up a lot.
*/
cal(yr, mon)
{
register xmon, pos;
register wday;
/*
* Start at 1 January, 1 which was a Saturday.
*/
wday = 6;
for (pos=1; pos<yr; pos++) {
if (pos == GREGYEAR)
wday -= GREGADJ;
wday = (wday + (isleap(pos) ? 366 : 365)) % 7;
}
baseday = wday;
if (mon != 0) {
fillcal(0, mon, yr);
outcal(mon, 1);
} else {
printf("\n%*d\n", CENTRE, yr);
pos = 0;
for (xmon = 1; xmon <= 12; xmon++) {
fillcal(pos, xmon, yr);
if (++pos >= MPL) {
outcal(xmon-MPL+1, MPL);
pos = 0;
}
}
}
}
/*
* Fill the caldays array element for the particular month
* and year specified.
*/
fillcal(pos, month, year)
{
register i, j, day;
int wday, special, mdays;
for (i=0; i<6; i++)
for (j=0; j<7; j++)
caldays[pos][i][j] = 0;
wday = baseday;
dpm[FEB] = isleap(year) ? 29 : 28;
special = (year==GREGYEAR);
for (i=1; i<month; i++) {
if (special && i==GREGMON)
wday -= GREGADJ;
wday = (wday + dpm[i]) % 7;
}
special = (special && month==GREGMON);
mdays = dpm[month];
i = 0;
j = wday;
for (day = 1; day <= mdays; day++) {
caldays[pos][i][j] = day;
if (special && day==GREGDAY)
day += GREGADJ;
if (++j >= 7) {
j = 0;
i++;
}
}
}
/*
* Put out `n' months from caldays, starting at month `mon'.
*/
outcal(mon, n)
{
register i, j, k;
int left, cent;
int val;
char *name;
mon--;
lput('\n');
for (i=1; i<=n; i++) {
name = mnames[mon++];
cent = strlen(name);
left = (DAYWIDTH-cent)/2;
spaceover(left);
lputs(name);
spaceover(DAYWIDTH+GAP-left-cent);
}
lput('\n');
for (i=1; i<=n; i++) {
lputs(dayhead);
spaceover(GAP);
}
lput('\n');
for (j=0; j<6; j++) {
for (i=0; i<n; i++) {
for (k=0; k<7; k++) {
lput(' ');
val = caldays[i][j][k];
lput(val>=10 ? val/10 + '0' : ' ');
if (val)
lput(val%10 + '0');
else
lput(' ');
}
spaceover(GAP);
}
lput('\n');
}
}
/*
* Put out calendar characters saving them up until a
* newline so that trailing blanks can be stripped.
*/
static char lline[100];
static char *lp = lline;
lput(c)
register c;
{
register char *cp;
if (c != '\n')
*lp++ = c;
else {
for (cp = lp; *--cp == ' '; )
;
*++cp = '\n';
*++cp = '\0';
printf("%s", lp = lline);
}
}
/*
* Put out a string using `lput'.
*/
lputs(s)
register char *s;
{
while (*s != '\0')
lput(*s++);
}
spaceover(n)
register n;
{
if (n>0)
do {
lput(' ');
} while (--n);
}
/*
* Return 1 on leap years; 0 otherwise.
*/
isleap(yr)
register yr;
{
if (yr<=GREGYEAR)
return (yr%4 == 0);
if (yr%4000 == 0)
return (0);
if (yr%400==0 || (yr%100!=0 && yr%4==0))
return (1);
return (0);
}
/*
* Return the month (1-12) from `mname' which is
* roman numeric, the name in ascii of a month, or wrong.
* Trailing '.' is accepted as are upper case letters.
*/
struct months {
char *m_name;
int m_num;
} months[] = {
"i", JAN, "jan", JAN, "january", JAN,
"janvier", JAN, "ii", FEB, "feb", FEB,
"february", FEB, "fevrier", FEB, "iii", MAR,
"mar", MAR, "march", MAR, "mars", MAR,
"iv", APR, "apr", APR, "april", APR,
"avril", APR, "v", MAY, "may", MAY,
"mai", MAY, "vi", JUN, "jun", JUN,
"june", JUN, "juin", JUN, "vii", JUL,
"jul", JUL, "july", JUL, "juillet", JUL,
"viii", AUG, "iix", AUG, "aug", AUG,
"august", AUG, "aout", AUG, "ix", SEP,
"sep", SEP, "sept", SEP, "september", SEP,
"septembre", SEP, "x", OCT, "oct", OCT,
"october", OCT, "octobre", OCT, "xi", NOV,
"nov", NOV, "november", NOV, "novembre", NOV,
"xii", DEC, "dec", DEC, "december", DEC,
"decembre", DEC, NULL
};
getmon(mname)
char *mname;
{
register struct months *mp;
register char *p1, *p2;
for (p1 = mname; *p1 != '\0'; p1 += 1)
if (isupper(*p1))
*p1 = tolower(*p1);
if (*--p1 == '.')
*p1 = '\0';
for (mp = months; mp->m_name != NULL; mp++) {
p1 = mname;
p2 = mp->m_name;
while (*p1 == *p2 && *p1 != '\0' && *p2 != 0)
p1 += 1, p2 += 1;
if (*p1 == *p2)
return (mp->m_num);
}
return (-1);
}
usage()
{
fprintf(stderr, "Usage: cal [month] [year]\n");
exit(1);
}