Xref: utzoo comp.lang.c:24058 comp.text:5663 Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!ucsd!swrinde!cs.utexas.edu!mailrus!uflorida!stat!naras From: naras@stat.fsu.edu (B. Narasimhan) Newsgroups: comp.lang.c,comp.text Subject: A C program for a Calendar in LaTeX. Message-ID: <778@stat.fsu.edu> Date: 28 Nov 89 14:36:41 GMT Reply-To: naras@stat.fsu.edu (B. Narasimhan) Organization: Dept. of Statistics, Florida State Univ. Lines: 532 /* This is "lxcal.c", a C program to produce a Calendar in LaTeX. No * claim whatsoever is made regrading this code or the calendar-design. * Note that no error checking is done. * The calendar is printed on a 11in by 8.5in paper. Use your favorite * DVI2PS with the landsacpe option. * I found this to be a useful programming exercise both in C and LaTeX. * Comments, suggestions and reports regarding bugs are welcome. * Author: B. Narasimhan * Dept. of Statistics Florida State Univesrity * Tallahassee, FL 32306. * E-mail: naras@stat.fsu.edu * I wish to thank * William Poser * Dept. of Linguistics * Stanford University * who provided the string handling routines I needed, including a new * "itoa" and the person (I don't know the name) who posted the * day_of_week algorithm on the net. * Usage: lxcal [input_file] [output_file] * * Input should be as follows: YEAR MONTH - Integers DAY_NO - Integer \begin{itemize} \item Item_1 \\ \item Item_2 \\ ...... \item Item_N \\ \end{itemize} % ANOTHER DAY_NO - Integer \begin{itemize} .... \end{itemize} % * and so on. The % is important. This preempts the use of %. Can anyone * out there change this to %% instead? I tried the usual tricks and for * some reason they all bombed and I am not willing to spend more time on * this now. */ /* AN EXERCISE [M15]: This is a wrap-around calendar with 5 rows. Some time in the future the last row will be empty, i.e. February will have 28 days with the Ist day beginning on a Sunday. Which is the earliest year when this happens? Can you characterize those years (at least during your lifetime) ? */ #include #include #define CNULL ( ( char *) 0) #define MAXLEN 1000 static char *month_name[] = { "", "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" }; static int no_of_days[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; static int offsets[] = {0, 0, 3, 3, 6, 1, 4, 6, 2, 5, 7, 3, 5}; char *create_copy(string) char *string; /* * Copy a string and return a pointer to the new storage allocated * to contain it. This function differs from strcpy(3) in that it * allocates the necessary storage instead of just copying into * storage provided by the caller. */ { char *new; extern char *malloc(); if( (new = malloc( (unsigned) (strlen(string) + 1) ) ) != CNULL){ strcpy(new,string); } else fprintf(stderr,"create_copy: malloc error\n"); return(new); } char *copy_cat(string1,string2) char *string1, *string2; /* * Concatenate the strings in the two arguments, allocating the * necessary storage, freeing the storage allocated to the first * argument, and returning a pointer to the newly created object. * This function is similar to strcat(3) but differs from it in * handling the storage allocation as well as in destroying the * original first argument. */ { char *new; extern char *malloc(); extern void free(); if( (new = malloc( (unsigned) (strlen(string1) + strlen(string2) + 1) )) != CNULL){ strcpy(new,string1); strcat(new,string2); if(string1 != CNULL) free(string1); } else fprintf(stderr,"copy_cat: malloc error\n"); return(new); } /* * This is a fast subroutine for converting a binary * integer into a decimal ASCII string. It is very much * like the itoa routine described on p.60 of K&R, but differs * from it in several respects. One is the order of arguments. * The name of the string in which to write is given first in order * to be consistent with sprintf and kindred functions. * * This algorithm fails on the most negative integer. * */ void itoa(string,k) char *string; /* String in which to write */ int k; /* Integer to convert */ { register int temp; register char *s; register char *p; register int n; register int q; register int r; int sign; n = k; /* Copy integer into register */ p = s = string; /* Copy pointer into registers */ if( (sign = n) < 0) n = -n; /* Make n positive */ /* Do conversion */ do { q = n / 10; r = (q << 3) + (q << 1); /* Multiply by 10 (8x + 2x = 10x) */ *s++ = n + '0' - r; } while (( n = q) > 0); if(sign < 0) *s++ = '-'; /* If negative, add sign */ *s = '\0'; /* Null terminate string */ s--; /* Point s at last non-null char */ /* * Now we reverse the string. When we begin, p points at the first * character of the string, s at the last non-null character. */ while(p < s){ temp = *p; *p++ = *s; *s-- = temp; } return; } int day_of_week(year,month, day) int year, month,day; { int dw; dw=4+year+((year+3)/4)+offsets[month]+day; if( ((year%4) ==0) && (month > 2)) dw++; if( (year==0) && (month < 3)) dw++; dw=(dw%7); return(dw); } int days_in_month(year, month) int year, month; { int leap; leap = year%4 == 0 && year%100 !=0 || year%400 == 0; return(no_of_days[leap][month]); } char *read_event(fpi, p) /* Read LaTeX input and return pointer. */ FILE *fpi; char *p; { int i, lenp; char s[MAXLEN], *temp_p, *t; temp_p = p; lenp = strlen(p); if ((t = malloc((unsigned) lenp)) != CNULL) { for (i = 0; i < lenp - 1; i++) t[i] = *temp_p++; t[i] = '\0'; free(p); while ((i=fscanf(fpi,"%[^\%]",s)) != 0) { t = copy_cat(t," "); t = copy_cat(t, s); } t = copy_cat(t," }"); i = fscanf(fpi,"%s",s); } else fprintf(stderr,"read_event: malloc error\n"); return(t); } main(argc, argv) int argc; char *argv[]; { int year, month, day, result, prev, next, temp, cell_no; int days_now, days_prev, days_next, days_next_next; int day_one_now, day_one_next, day_one_prev; int which_day, next_month, prev_month, prev_month_year, next_month_year; int i, j; char buffer[10], *p; FILE *fpi, *fpo, *fopen(); struct day_info { int day_no; char *event; } list[35]; if (argc == 1) { fpi = stdin; fpo = stdout; } if (argc >= 2) if ((fpi = fopen(*++argv, "r")) == NULL) { fprintf(stderr,"lxcal: can't open %s\n",*argv); exit(1); } if (argc >= 3) if ((fpo = fopen(*++argv, "w")) == NULL) { fprintf(stderr,"lxcal: can't open %s\n",*argv); exit(1); } result = fscanf(fpi,"%d %d", &year, &month); /* Figure prev_month and prev_month_year, and same for next month. */ if (month == 1) { prev_month = 12; prev_month_year = year - 1; } else { prev_month = month - 1; prev_month_year = year; } if (month == 12) { next_month = 1; next_month_year = year + 1; } else { next_month_year = year; next_month = month + 1; } /* Figure starting week day in those months. */ day_one_now = day_of_week(year, month, 1); day_one_next = day_of_week(next_month_year, next_month, 1); day_one_prev = day_of_week(prev_month_year, prev_month, 1); /* Figure number of days in those months. */ days_now = days_in_month( year, month); days_prev = days_in_month( prev_month_year, prev_month); days_next = days_in_month( next_month_year, next_month); /* Determine where the sub-calendars for prev and next months go. */ temp = days_now + day_one_now; if (day_one_now == 0 && days_now == 28) { prev = 28; next = 34; } else if ( day_one_now == 0) { prev = 33; next = 34; } else if (temp <= 34) { prev = 0; next = 34; } else if (temp == 35) { prev = 0; next = 1; } else { prev = (temp+1)%7; next = prev + 1; } /* Mark the corresponding days with negative day_no's. (For output.) */ list[prev].day_no = -2; list[next].day_no = -1; /* Set the dates. */ for (i = day_one_now; i < day_one_now + 35; i++) { j = i%35; if (i >= days_now + day_one_now) list[j].day_no = 0; /* Mark boxes with no day numbers. */ else list[j].day_no = i - day_one_now + 1; if (j%7 != 0) list[j].event = create_copy(" &\\boxit{\n }"); else list[j].event = create_copy(" \\boxit{\n }"); } /* Now set about arranging things for the sub-calendars. */ if (prev%7 == 0) list[prev].event = create_copy(" "); else list[prev].event = create_copy(" &"); list[prev].event = copy_cat(list[prev].event,"\\boxcal{\n \\"); list[prev].event = copy_cat(list[prev].event,"begin{center}\n "); list[prev].event = copy_cat(list[prev].event, month_name[prev_month]); list[prev].event = copy_cat(list[prev].event, " "); itoa(buffer, prev_month_year); list[prev].event = copy_cat(list[prev].event,buffer); list[prev].event = copy_cat(list[prev].event,"\n \\end{center}\n"); list[prev].event = copy_cat(list[prev].event," \\begin{tabular*}"); list[prev].event = copy_cat(list[prev].event,"{1.30in}{rrrrrrr}\n"); list[prev].event = copy_cat(list[prev].event," \\hline\n "); list[prev].event = copy_cat(list[prev].event,"S &M &T &W &T "); list[prev].event = copy_cat(list[prev].event,"&F &S \\\\\n"); list[prev].event = copy_cat(list[prev].event," \\hline\n"); for (i = 0; i < days_prev+day_one_prev; i++) { if (i%7 == 0) list[prev].event = copy_cat(list[prev].event," "); else list[prev].event = copy_cat(list[prev].event," &"); if (i >= day_one_prev) { itoa(buffer,i-day_one_prev+1); list[prev].event = copy_cat(list[prev].event,buffer); } if (i%7 == 6) list[prev].event = copy_cat(list[prev].event,"\\\\\n"); } list[prev].event = copy_cat(list[prev].event,"\n "); list[prev].event = copy_cat(list[prev].event,"\\end{tabular*}\n }"); if (next%7 == 0) list[next].event = create_copy(" "); else list[next].event = create_copy(" &"); list[next].event = copy_cat(list[next].event,"\\boxcal{\n \\"); list[next].event = copy_cat(list[next].event,"begin{center}\n "); list[next].event = copy_cat(list[next].event, month_name[next_month]); list[next].event = copy_cat(list[next].event, " "); itoa(buffer,next_month_year); list[next].event = copy_cat(list[next].event, buffer); list[next].event = copy_cat(list[next].event,"\n \\end{center}\n"); list[next].event = copy_cat(list[next].event," \\begin{tabular*}"); list[next].event = copy_cat(list[next].event,"{1.30in}{rrrrrrr}\n"); list[next].event = copy_cat(list[next].event," \\hline\n S"); list[next].event = copy_cat(list[next].event," &M &T &W &T &F"); list[next].event = copy_cat(list[next].event," &S \\\\\n \\hline\n"); for (i = 0; i < days_next+day_one_next; i++) { if (i%7 == 0) list[next].event = copy_cat(list[next].event," "); else list[next].event = copy_cat(list[next].event," &"); if (i >= day_one_next) { itoa(buffer,i-day_one_next+1); list[next].event = copy_cat(list[next].event,buffer); } if (i%7 == 6) list[next].event = copy_cat(list[next].event,"\\\\\n"); } list[next].event = copy_cat(list[next].event,"\n \\"); list[next].event = copy_cat(list[next].event,"end{tabular*}\n }"); /* Read the events for the present month. */ result = fscanf(fpi,"%d",&which_day); while (result != 0 && result != EOF) { temp = (which_day + day_one_now +34)%35; list[temp].event = read_event(fpi, list[temp].event); result = fscanf(fpi,"%d",&which_day); } /* Just print out the LaTeX file! */ fprintf(fpo,"%s","\% This is a Calendar in LaTeX.\n"); fprintf(fpo,"%s","\% Author: B. Narasimhan\n"); fprintf(fpo,"%s","\% Dept. of Statistics\n"); fprintf(fpo,"%s","\% Florida State University\n"); fprintf(fpo,"%s","\% Tallahassee, FL 32306-3033\n"); fprintf(fpo,"%s","\% Ph. (904)-644-5852\n"); fprintf(fpo,"%s","\% E-mail: naras@stat.fsu.edu\n"); fprintf(fpo,"%s","\% Freely redistributable and modifyable. \n"); fprintf(fpo,"%s","\% Modifiers and enhancers, please:\n"); fprintf(fpo,"%s","\% 1. Make sure credit is given to all"); fprintf(fpo,"%s"," involved\n"); fprintf(fpo,"%s","\% and more importantly,\n"); fprintf(fpo,"%s","\% 2. Mail me a copy for the sake of"); fprintf(fpo,"%s"," improving my knowledge.\n" ); fprintf(fpo,"%s","\%\n"); fprintf(fpo,"%s","\\documentstyle[12pt]{article}\n"); fprintf(fpo,"%s","\%\n"); fprintf(fpo,"%s","\\newcommand{\\boxit}[1]{\\vbox to 81pt{\\"); fprintf(fpo,"%s","begin{minipage}[b]{1.30in}\n"); fprintf(fpo,"%s","\\setlength{\\parskip}{0.0in}\n"); fprintf(fpo,"%s","\\setlength{\\baselineskip}{3.0mm}\n"); fprintf(fpo,"%s","\\raggedright #1 \\end{minipage}\n"); fprintf(fpo,"%s","\\vspace{\\fill}}}\n"); fprintf(fpo,"%s","\%\n"); fprintf(fpo,"%s","\\newcommand{\\boxcal}[1]{\\vbox to 81pt{\\"); fprintf(fpo,"%s","begin{minipage}[b]{1.30in}\n"); fprintf(fpo,"%s","\\setlength{\\arrayrulewidth}{0.01mm} \n"); fprintf(fpo,"%s","\\renewcommand{\\arraystretch}{0.60} \n"); fprintf(fpo,"%s","\\trsix\n"); fprintf(fpo,"%s","\\setlength{\\baselineskip}{1.90mm} \n"); fprintf(fpo,"%s","\\setlength{\\tabcolsep}{0.6em} \n"); fprintf(fpo,"%s","#1\\end{minipage}\\vspace{\\fill}}}\n"); fprintf(fpo,"%s","\%\n"); fprintf(fpo,"%s","\\setlength{\\topskip}{0.0in}\n"); fprintf(fpo,"%s","\\setlength{\\headheight}{0.0in}\n"); fprintf(fpo,"%s","\\setlength{\\headsep}{0.0in}\n"); fprintf(fpo,"%s","\\setlength{\\footheight}{0.0in}\n"); fprintf(fpo,"%s","\\setlength{\\footskip}{0.4375in}\n"); fprintf(fpo,"%s","\\setlength{\\topmargin}{-.5625in}\n"); fprintf(fpo,"%s","\\setlength{\\oddsidemargin}{-0.65in}\n"); fprintf(fpo,"%s","\\setlength{\\textwidth}{10.3in}\n"); fprintf(fpo,"%s","\\setlength{\\textheight}{8.5in}\n"); fprintf(fpo,"%s","\\newfont{\\hb}{h-bol at 12pt}\n"); fprintf(fpo,"%s","\\newfont{\\hbbig}{h-bol at 24pt}\n"); fprintf(fpo,"%s","\\newfont{\\tbeight}{t-bol at 8pt}\n"); fprintf(fpo,"%s","\\newfont{\\treight}{t-rom at 8pt}\n"); fprintf(fpo,"%s","\\newfont{\\tbieight}{t-bolita at 8pt}\n"); fprintf(fpo,"%s","\\newfont{\\tb}{t-bol at 12pt}\n"); fprintf(fpo,"%s","\\newfont{\\trsix}{t-rom at 6pt}\n"); fprintf(fpo,"%s","\\pagestyle{empty}\n"); fprintf(fpo,"%s","\\begin{document}\n"); fprintf(fpo,"%s","\\treight\n"); fprintf(fpo,"%s","\\vspace{\\fill}\n"); fprintf(fpo,"%s","\\begin{center}\n"); fprintf(fpo,"%s"," {\\hbbig "); fprintf(fpo,"%s ",month_name[month]); fprintf(fpo," "); itoa(buffer, year); fprintf(fpo,"%s",buffer); fprintf(fpo,"%s","}\n\\end{center}\n"); fprintf(fpo,"%s","\\begin{tabular}{|p{1.30in}|p{1.30in}|p{1.30in}"); fprintf(fpo,"%s","|p{1.30in}|p{1.30in}|p{1.30in}|p{1.30in}|}\n"); fprintf(fpo,"%s"," \\hline\n"); fprintf(fpo,"%s"," \\multicolumn{1}{|c}{\\hb Sunday}\n"); fprintf(fpo,"%s"," &\\multicolumn{1}{|c}{\\hb Monday}\n"); fprintf(fpo,"%s"," &\\multicolumn{1}{|c}{\\hb Tuesday}\n"); fprintf(fpo,"%s"," &\\multicolumn{1}{|c}{\\hb Wednesday}\n"); fprintf(fpo,"%s"," &\\multicolumn{1}{|c}{\\hb Thursday}\n"); fprintf(fpo,"%s"," &\\multicolumn{1}{|c}{\\hb Friday}\n"); fprintf(fpo,"%s"," &\\multicolumn{1}{|c|}{\\hb Saturday}\n"); fprintf(fpo,"%s"," \\\\ \n"); fprintf(fpo,"%s"," \\hline\\hline"); for (i = 0; i < 5; i++) { for (j = 0; j < 7; j++) { cell_no = i*7 + j; if (cell_no%7 == 0) fprintf(fpo," "); else fprintf(fpo," &"); if (list[cell_no].day_no <= 0 ) fprintf(fpo,"\n"); else if (cell_no%7 == 6 || list[cell_no].day_no == days_now) { fprintf(fpo,"%s","\\multicolumn{1}{|r|}{\\tb "); itoa(buffer,list[cell_no].day_no); fprintf(fpo,"%s}\n",buffer); } else { fprintf(fpo,"%s","\\multicolumn{1}{|r}{\\tb "); itoa(buffer,list[cell_no].day_no); fprintf(fpo,"%s}\n",buffer); } } fprintf(fpo," \\\\\n"); for (j = 0; j < 7; j++) { cell_no = i*7 + j; fprintf(fpo,"%s\n",list[cell_no].event); } fprintf(fpo,"%s"," \\\\\n \\hline\n"); } /* Close open environments. */ fprintf(fpo,"%s","\\end{tabular}\n"); fprintf(fpo,"%s","\\vspace{\\fill}\n"); fprintf(fpo,"%s","\\end{document}\n"); /* Return heap space. */ for (i = 0; i < 35; i++) free(list[i].event); /* Close files. */ fclose(fpi); fclose(fpo); } Sample input-----------CUT HERE---------- 1989 12 4 \begin{itemize} \item Oral Presentation. \\ \item 6:30pm Dinner date with Brokujam. \end{itemize} % 7 \begin{itemize} \item Mom's Birthday. \\ \item 10:00am Dentist Appointment. \end{itemize} % 30 \begin{itemize} \item Duds Anonymous meeting. \\ \item Party till death \end{itemize} % Brought to you by Super Global Mega Corp .com