#include <conio.h>
#include <ctype.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define DEBUG
#define EOS ('\0')
#define bool char
#define In(x,y,z) ((x)<=(y) && (y)<=(z))
#define Min(x,y) ((x)<(y) ? (x) : (y))
#define Max(x,y) ((x)>(y) ? (x) : (y))
#define streq !strcmp
enum {weekly,monthly,yearly};
void create_calendar(void);
void exit_here(bool opt,const char *format,...);
int get_day_of_week(int year,int month,int day);
void get_second_field_parameters(char *string);
void get_third_field_parameters(char *string);
void get_today(void);
bool leap_year(int year);
int n_rows_in_monthly_calendar(int year,int month,int dw);
void preprocess(int argc,char *argv[]);
void show_usage(void);
int str2num(char *str);
void write_calendar_page(int n,FILE *fp_out);
int CalendarType; /* weekly=0, monthly=1 or yearly=2 */
int Npages; /* -n */
int MperPage=1; /* m in -n,m. For "monthly" only. */
int StartYear,StartMonth,StartDay; /* [year/month/day] */
/* Above are determined in preprocess(),
from the command line. */
int Days_of_month[12]={31,28,31,30,31,30,31,31,30,31,30,31};
char *MonthName[12]={"January","February","March","April",
"May","June","July","August",
"September","October","November","December"},
*Month_name[12]={"Jan","Feb","Mar","Apr",
"May","Jun","Jul","Aug",
"Sep","Oct","Nov","Dec"};
char *DayName[7]={"Sunday","Monday","Tuesday","Wednesday",
"Thursday","Friday","Saturday"},
*Day_name[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
int ThisYear,ThisMonth,Today; /* Counts from one. */
void main(int argc,char *argv[])
{
char *calendartype[3]={"weekly","monthly","yearly"};
if(!In(2,argc,4)) show_usage();
get_today();
preprocess(argc,argv);
if(MperPage>=4) exit_here(0,"This option not available yet.");
printf("\nWe'll create %d page",Npages);
if(Npages>1) printf("s");
printf(" of %s calendar starting from %d",
calendartype[CalendarType],StartYear);
if(CalendarType==weekly) printf("/%d/%d.\n",StartMonth,StartDay);
else if(CalendarType==monthly){
printf("/%d.\nMonth per page = %d.\n",StartMonth,MperPage);
}
else printf(".\n");
cprintf("\r\nContinue ? (y/n): ");
if(getche()!='y') exit_here(0,"\nAborted by user request.");
create_calendar();
printf("\nExecute \"latex calendar\".\n");
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void preprocess(int argc,char *argv[])
{
char *p;
/* first field, CalendarType */
if(argv[1][0]!='-') show_usage();
if(streq((p=&(argv[1][1])),"w") || streq(p,"weekly"))
CalendarType = weekly;
else if(streq(p,"m") || streq(p,"monthly")) CalendarType = monthly;
else if(streq(p,"y") || streq(p,"yearly")) CalendarType = yearly;
else show_usage();
/* give default values, tentatively */
Npages = 1;
StartYear = ThisYear;
StartMonth = ThisMonth;
StartDay = Today; /* year day */
if(argv[2][0]=='-'){
get_second_field_parameters(&(argv[2][1]));
if(argc==4) get_third_field_parameters(argv[3]);
else if(argc!=3) show_usage();
}
else if(argc==3) get_third_field_parameters(argv[2]);
else if(argc!=2) show_usage();
}
/* -------------------------------------- */
void show_usage(void)
{
printf("\nUsage: nemocal -options [-n[,m]] [year/month/day]\n\n\
where -options = -w[eekly]|-m[onthly]|-y[early]\n\
-n = number of pages\n\
m = number of months in a page (for -monthly only)\n\
year/month/day = start of the calendar\n\n");
exit(0);
}
/* -------------------------------------- */
void print_rows(int rows,int dw,int dmon,bool center,
int width,int height6,int height5,
int depth6,int depth5,FILE *fp_out)
{ /* for monthly calendars only */
int x,row,i;
char xstr[21];
x = 0;
for(row=0;row<rows;row++){
for(i=0;i<7;i++){
if(i==0){
if(rows<6)
fprintf(fp_out,"\\rule[-%dpt]{0pt}{%dpt} ",depth5,height5);
else fprintf(fp_out,"\\rule[-%dpt]{0pt}{%dpt} ",depth6,height6);
}
else fprintf(fp_out," ");
if(row==0){
if(i<dw) x = 0;
else x++;
}
else{
if(x!=0) x++;
if(x>dmon) x = 0;
}
if(x==0) strcpy(xstr," ");
else sprintf(xstr,"%d",x);
if(center){
if(i<6) fprintf(fp_out,"\\makebox[%dpt]{%s} &\n",width,xstr);
else fprintf(fp_out,"\\makebox[%dpt]{%s} \\\\ \\hline\n",
width,xstr);
}
else{
if(i<6) fprintf(fp_out,"\\makebox[%dpt][r]{%s} &\n",width,xstr);
else fprintf(fp_out,"\\makebox[%dpt][r]{%s} \\\\ \\hline\n",
width,xstr);
}
}
}
}
/* -------------------------------------- */
void create_calendar(void)
{
FILE *fp_out;
int n;
fp_out = fopen("calendar.tex","wt");
if(fp_out==NULL) exit_here(1,"Can't create calendar.tex.");
cprintf("\r\n\nCreating calendar.tex");
fprintf(fp_out,"\\documentstyle{article}\n\n");
fprintf(fp_out,"\\oddsidemargin 0cm\n");
fprintf(fp_out,"\\evensidemargin 0cm\n");
if(CalendarType==weekly) fprintf(fp_out,"\\topmargin -1cm\n");
else fprintf(fp_out,"\\topmargin -1.6cm\n");
fprintf(fp_out,"\\parindent 0cm\n");
if(CalendarType!=monthly || (MperPage!=1 && MperPage!=4)){
/* Portrait mode */
fprintf(fp_out,"\\textheight 11in\n");
fprintf(fp_out,"\\textwidth 16.44cm\n");
}
else{ /* Landscape mode */
fprintf(fp_out,"\\textheight 7.0in\n");
fprintf(fp_out,"\\textwidth 9.0in\n");
}
fprintf(fp_out,"\\pagestyle{empty}\n\n");
fprintf(fp_out,"\\begin{document}\n\n");
for(n=1;n<=Npages;n++){
write_calendar_page(n,fp_out);
cprintf(" [%d]",n);
}
fprintf(fp_out,"\\end{document}\n\n");
fclose(fp_out);
printf(" Done.\n");
if(CalendarType==monthly && (MperPage==1 || MperPage==4))
printf("\nRemember the landscape mode!\n");
}
/* -------------------------------------- */
void write_calendar_page(int n,FILE *fp_out)
{
int startmonth,endmonth,startyear,endyear,
d_Sun,dw,i,j,k,days_remaining,day,dmon,rows,month;
char month_str[21],year_str[21];
if(n>1) fprintf(fp_out,"\\newpage\n");
if(CalendarType==weekly){
/* for weekly calendars, one page may have two months/years */
dw = get_day_of_week(StartYear,StartMonth,StartDay);
if(StartDay>=dw){
d_Sun = StartDay - dw + 1;
startyear = endyear = StartYear;
startmonth = endmonth = StartMonth;
days_remaining = Days_of_month[StartMonth-1] - StartDay;
if(StartMonth==2 && leap_year(StartYear)) days_remaining++;
if(days_remaining<7-dw){
if(StartMonth<12) endmonth = startmonth+1;
else{
endmonth = 1;
endyear = StartYear+1;
}
}
}
else{
if(StartMonth>1){
startyear = endyear = StartYear;
startmonth = StartMonth-1;
endmonth = StartMonth;
}
else{
startyear = StartYear - 1;
endyear = StartYear;
startmonth = 12;
endmonth = 1;
}
d_Sun = Days_of_month[startmonth-1] - dw + 2;
if(startmonth==2 && leap_year(startyear)) d_Sun++;
}
if(endmonth==startmonth)
sprintf(month_str,"%s",Month_name[startmonth-1]);
else sprintf(month_str,"%s/%s",
Month_name[startmonth-1],Month_name[endmonth-1]);
if(endyear==startyear) sprintf(year_str,"%d",startyear);
else sprintf(year_str,"%d/%d",startyear,endyear);
if(n%2==1) fprintf(fp_out,
"{\\large\\sf\n\\hfill %s \\ %s\n}\n\\vspace{1cm}\n\n",
month_str,year_str);
else fprintf(fp_out,"{\\large\\sf\n %s \\ %s\n}\n\\vspace{1cm}\n\n",
month_str,year_str);
fprintf(fp_out,"\\begin{tabular}{|c|c|} \\hline\n");
for(i=1;i<=7;i++){
day = d_Sun + i - 1;
if(day>(dmon = Days_of_month[startmonth-1] +
(startmonth==2 && leap_year(startyear))))
day -= dmon;
fprintf(fp_out,"\\rule{0cm}{1.5cm}{\\Huge %d}\
& \\rule{13.68cm}{0cm} \\\\ \n",day);
fprintf(fp_out,"\\rule{0cm}{1cm}\\raisebox{.1cm}{\\sf %s}\
& \\\\ \\hline \n",DayName[i-1]);
}
fprintf(fp_out,"\\end{tabular}\n\n");
StartDay += 7;
if(StartDay > (dmon = Days_of_month[StartMonth-1] +
(StartMonth==2 && leap_year(StartYear)))){
StartDay -= dmon;
StartMonth++;
if(StartMonth>12){ StartMonth = 1; StartYear++; }
}
}
else if(CalendarType==monthly){
switch(MperPage){
case 1:
dw = get_day_of_week(StartYear,StartMonth,1) - 1;
/* Sunday=0,Monday=1 etc. for no good reason */
rows = n_rows_in_monthly_calendar(StartYear,StartMonth,dw);
if(rows<6) fprintf(fp_out,"\\rule{0cm}{0.6cm}\n");
fprintf(fp_out,"\\begin{center}\n\n");
fprintf(fp_out,"{\\huge\\sf %s \\rule{1.5em}{0em} %d}\n\n",
MonthName[StartMonth-1],StartYear);
fprintf(fp_out,"\\rule{0em}{3em}\n\n");
fprintf(fp_out,"{\\Large\\sf\n");
fprintf(fp_out,"\\begin{tabular}{|c|c|c|c|c|c|c|} \\hline\n");
fprintf(fp_out,"\\rule[-3mm]{0mm}{10mm}");
for(i=0;i<7;i++){
fprintf(fp_out,"\\makebox[71pt]{%s}",Day_name[i]);
if(i<6) fprintf(fp_out," &\n");
}
fprintf(fp_out," \\\\ \\hline\n");
dmon = Days_of_month[StartMonth-1] +
(StartMonth==2 && leap_year(StartYear));
print_rows(rows,dw,dmon,0,71,65,71,48,54,fp_out);
fprintf(fp_out,"\\end{tabular}\n");
fprintf(fp_out,"}\n\n");
fprintf(fp_out,"\\end{center}\n\n");
StartMonth++;
if(StartMonth>12){ StartMonth = 1; StartYear++; }
break;
case 2:
for(j=0;j<2;j++){
if(j==0) fprintf(fp_out,"\\rule{0cm}{0.5cm}\n");
else fprintf(fp_out,"\\rule{0cm}{1.5cm}\n");
dw = get_day_of_week(StartYear,StartMonth,1) - 1;
/* Sunday=0,Monday=1 etc. for no good reason */
rows = n_rows_in_monthly_calendar(StartYear,StartMonth,dw);
fprintf(fp_out,"\\begin{center}\n\n");
fprintf(fp_out,"{\\Large\\sf %s \\rule{1.5em}{0em} %d}\n\n",
MonthName[StartMonth-1],StartYear);
fprintf(fp_out,"\\rule{0em}{2em}\n\n");
fprintf(fp_out,"{\\large\\sf\n");
fprintf(fp_out,"\\begin{tabular}{|c|c|c|c|c|c|c|} \\hline\n");
fprintf(fp_out,"\\rule[-7pt]{0pt}{22pt}");
for(i=0;i<7;i++){
fprintf(fp_out,"\\makebox[43pt]{%s}",Day_name[i]);
if(i<6) fprintf(fp_out," &\n");
}
fprintf(fp_out," \\\\ \\hline\n");
dmon = Days_of_month[StartMonth-1] +
(StartMonth==2 && leap_year(StartYear));
print_rows(rows,dw,dmon,0,43,37,43,25,31,fp_out);
fprintf(fp_out,"\\end{tabular}\n");
fprintf(fp_out,"}\n\n");
fprintf(fp_out,"\\end{center}\n\n");
StartMonth++;
if(StartMonth>12){ StartMonth = 1; StartYear++; }
}
break;
/* case 4 and case 6 not available yet */
}
}
else{ /* yearly */
fprintf(fp_out,"\\begin{center}\n");
fprintf(fp_out,"{\\huge\\sf %d}\n",StartYear);
fprintf(fp_out,"\\end{center}\n\n");
for(j=0;j<4;j++){ /* each j corrsponds to three months */
if(j==0) fprintf(fp_out,"\\rule{0cm}{3.5cm}\n");
else fprintf(fp_out,"\\rule{0cm}{3.0cm}\n");
for(k=0;k<3;k++){
fprintf(fp_out,"\\parbox{4.8cm}{\n");
/* Write a monthly calendar here. */
month = j*3 + k + 1;
dw = get_day_of_week(StartYear,month,1) - 1;
/* Sunday=0,Monday=1 etc. for no good reason */
rows = n_rows_in_monthly_calendar(StartYear,month,dw);
fprintf(fp_out,"\\begin{center}\n\n");
fprintf(fp_out,"{\\sf %s}\n\n",MonthName[month-1]);
fprintf(fp_out,"\\rule{0em}{1em}\n\n");
fprintf(fp_out,"{\\sf\n");
fprintf(fp_out,"\\begin{tabular}{|c|c|c|c|c|c|c|} \\hline\n");
fprintf(fp_out,"\\rule[-3pt]{0pt}{11pt}");
for(i=0;i<7;i++){
fprintf(fp_out,"\\makebox[7pt]{\\footnotesize %s}",Day_name[i]);
if(i<6) fprintf(fp_out," &\n");
}
fprintf(fp_out," \\\\ \\hline\n");
dmon = Days_of_month[month-1] +
(month==2 && leap_year(StartYear));
print_rows(rows,dw,dmon,1,7,8,11,-2,0,fp_out);
fprintf(fp_out,"\\end{tabular}\n");
fprintf(fp_out,"}\n\n");
fprintf(fp_out,"\\end{center}\n\n");
if(k<2) fprintf(fp_out,"}\\rule{0.9cm}{0cm}\n");
else fprintf(fp_out,"} \\\\ \n");
}
}
StartYear++;
}
}
/*
*
* void exit_here(bool opt,const char *format,...)
* Prints formatted error messages on stdout and exits.
*
* int get_day_of_week(int year,int month,int day)
* Sun=1,Mon=2 etc.
*
* void get_second_field_parameters(char *string)
* Computes the global variable(s) Npages (and MperPage) from the
* input string -n[,m].
*
* void get_third_field_parameters(char *string)
* Computes the global variables StartYear,StartMonth and StartDay
* from the input string year/month/day. The CalendarType strongly
* affects the way this routine calculates those values.
*
* void get_today(void)
*
* bool leap_year(int year)
*
* int n_rows_in_monthly_calendar(int year,int month,int dw)
* year is to determine leap year.
* dw is day of the week counting from zero.
*
* int str2num(char *str)
*
*/
void exit_here(bool opt,const char *format,...)
{ /* opt==0 iff doesn't show !*** ERROR ***! */
char buffer[401];
va_list argp;
/* write to {\tt buffer[]} */
va_start(argp,format);
vsprintf(buffer,format,argp);
va_end(argp);
/* print the message and exit */
printf("\n");
if(opt) printf("!*** ERROR ***! ");
printf("%s\n\n",buffer);
exit(1);
}
/* -------------------------------------- */
int get_day_of_week(int year,int month,int day)
{ /* 1994/1/1 is Saturday */
int day_1_1, /* day of the week of Jan 1 of the input year */
day_m_1, /* day of the week of year/month/1 */
delta,n;
/* get day_1_1 */
delta = 0;
if(year>=1994){
for(n=1994;n<year;n++){
delta++;
if(leap_year(n)) delta++;
}
}
else{
for(n=year;n<1994;n++){
delta++;
if(leap_year(n)) delta++;
}
delta = -delta;
}
day_1_1 = (delta + 6)%7 + 1;
/* get day_m_1 */
delta = 0;
for(n=0;n<month-1;n++){
delta += Days_of_month[n];
if(n==1 && leap_year(year)) delta++;
}
day_m_1 = (delta+day_1_1-1)%7 + 1;
return (day_m_1 + day - 2)%7 + 1;
}
/* -------------------------------------- */
void get_second_field_parameters(char *string)
{
int x,pos,vpos;
char c,str1[11],str2[11];
if((x=str2num(string)) >= 0) Npages = x;
else{
if(CalendarType!=monthly) show_usage();
pos = vpos = 0;
while((c=string[pos++])!=',' && c!=EOS){
if(vpos>10) show_usage();
str1[vpos++] = c;
}
if(c!=',') show_usage();
str1[vpos] = EOS;
if((Npages=str2num(str1))<0) show_usage();
vpos = 0;
while((c=string[pos++])!=EOS){
if(vpos>=10) show_usage();
str2[vpos++] = c;
}
str2[vpos] = EOS;
if((MperPage=str2num(str2))<0) show_usage();
if(MperPage!=1 && MperPage!=2 && MperPage!=4 && MperPage!=6)
exit_here(0,"You can have only 1,2,4 or 6 months per page.");
}
}
/* -------------------------------------- */
void get_third_field_parameters(char *string)
{
int n=0; /* number of subfields separated by / */
char numstring[3][5];
int pos=0,vpos=0,i;
char c;
while((c=string[pos++])!=EOS){
if(c=='/'){
if(n>=2) show_usage();
numstring[n++][vpos] = EOS;
vpos = 0;
}
else{
if(vpos>=4) show_usage();
numstring[n][vpos++] = c;
}
}
numstring[n++][vpos] = EOS;
for(i=0;i<n;i++){
if(str2num(numstring[i])<=0) show_usage();
}
switch(CalendarType){ /* StartXxxx */
case weekly:
if(n==1) StartDay = str2num(numstring[0]);
else if(n==2){
StartMonth = str2num(numstring[0]);
StartDay = str2num(numstring[1]);
}
else if(n==3){
StartYear = str2num(numstring[0]);
StartMonth = str2num(numstring[1]);
StartDay = str2num(numstring[2]);
}
break;
case monthly:
if(n==1) StartMonth = str2num(numstring[0]);
else if(n==2){
StartYear = str2num(numstring[0]);
StartMonth = str2num(numstring[1]);
}
else exit_here(0,"No need to specify the day.");
break;
case yearly:
if(n!=1) exit_here(0,"No need to specify the month or day.");
StartYear = str2num(numstring[0]);
break;
}
}
/* -------------------------------------- */
void get_today(void)
{
time_t time_of_day;
auto struct tm *tmbuf;
time_of_day = time(NULL);
tmbuf = localtime(&time_of_day);
Today = tmbuf->tm_mday;
ThisMonth = tmbuf->tm_mon + 1;
ThisYear = tmbuf->tm_year + 1900;
}
/* -------------------------------------- */
bool leap_year(int year)
{
if(year%4 == 0){
if(year%100 == 0){
if(year%400 == 0) return 1;
else return 0;
}
else return 1;
}
else return 0;
}
/* -------------------------------------- */
int n_rows_in_monthly_calendar(int year,int month,int dw)
{
int rows=1,i,dmon;
dmon = Days_of_month[month-1] + (month==2 && leap_year(year));
for(i=2;i<=dmon;i++){
if((i+dw)%7 == 1) rows++;
}
return rows;
}
/* -------------------------------------- */
int str2num(char *str)
{ /* Returns 0 <= x <= 29999 normally.
Returns -1 if input is illegal. */
char c;
int n=0,pos=0;
while((c=str[pos])!=EOS){
if(!isdigit(c)) return -1;
n = n*10 + c - '0';
pos++;
}
if(pos>5 || (pos==5 && str[0]>'2')) return -1;
else return n;
}