home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Header: utils.c,v 2.2 89/05/16 16:30:18 billr Exp $
- */
- /*
- * utils.c
- *
- * calentool - a year/month/week/day-at-a-glance calendar for Sun workstations.
- *
- * Author: Philip Heller, Sun Microsystems. Inc. <terrapin!heller@sun.com>
- *
- * Original source Copyright (C) 1987, Sun Microsystems, Inc.
- * All Rights Reserved
- * Permission is hereby granted to use and modify this program in source
- * or binary form as long as it is not sold for profit and this copyright
- * notice remains intact.
- *
- *
- * Changes/additions by: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
- *
- * Changes and additions Copyright (C) 1988, 1989 Tektronix, Inc.
- * All Rights Reserved
- * Permission is hereby granted to use and modify the modifications in source
- * or binary form as long as they are not sold for profit and this copyright
- * notice remains intact.
- */
- /********************************************
- * *
- * Utility routines. *
- * *
- ********************************************/
-
-
-
- #include "ct.h"
- #include <stdio.h>
- #include <suntool/sunview.h>
- #include <suntool/canvas.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/file.h>
- #include <sys/stat.h>
- #include <sys/errno.h>
-
-
- extern struct tm today, current;
- extern struct tm First;
- extern int day_is_open, read_only;
- extern struct dayslot slots[];
- extern char apts_pathname[], tmpapts_pathname[];
- extern int dayslot_width, nr_weekdays, n_tslots;
- extern int dayslot_height;
- extern char *monthnames[], *daynames[];
- extern char *mailto, *progname;
- extern int one_based, version2, new_entry;
- extern int findex;
- extern struct appt_entry future[];
- extern char todays_date[];
- extern char apts_dir[], lib_dir[];
- extern char printer[];
- extern int include_old, save_old;
- extern Frame frame;
- extern Canvas canvas;
- extern Pixwin *main_pixwin;
- extern int mainsw_state;
- extern Pixfont *font, *sfont;
- extern Frame prompt_frame;
- extern int update_interval;
- extern int errno;
-
- char inbuf[512], strbuf[256], errbuf[64];
- char todays_date[32];
- static int including;
- static int log_to_console;
- char *daynames[] = {"Sunday","Monday","Tuesday","Wednesday",
- "Thursday","Friday","Saturday"};
- char *monthnames[] = {"January","February","March","April",
- "May","June","July","August",
- "September","October","November","December"};
- char *dayname[7] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
- char rasfile[] = "/usr/tmp/calentool.ras";
- char psfile[] = "/usr/tmp/calentool.ps";
- char *fname = 0;
-
- extern char *strcpy(), *strcat();
-
- /*
- * sets "today" and current time
- */
- void
- get_today()
- {
- struct tm *tm;
- struct timeval tv;
-
- gettimeofday(&tv, 0);
- tm = localtime(&tv.tv_sec);
-
- today = *tm;
-
- strcpy(todays_date, asctime(tm));
- if (update_interval >= 60)
- /* overwrite seconds field with year */
- sprintf(&todays_date[16], " %d", today.tm_year+1900);
- else
- /* just delete trailing \n */
- todays_date[strlen(todays_date)-1] = '\0';
- }
-
- /*
- * Reset some values in current tm structure. Year, month and
- * day-of-month are valid but day and/or month may be < 0 or
- * greater than the maximum value, in which case they are adjusted
- * accordingly. Day-of-year and day-of-week are then recalculated.
- */
- void
- fix_current_day()
- {
- int month, totdays = 0;
- struct tm from, to;
-
- if (current.tm_mon < JAN) {
- current.tm_mon = DEC;
- current.tm_year--;
- } else if (current.tm_mon > DEC) {
- current.tm_mon = JAN;
- current.tm_year++;
- }
- if (current.tm_mday < 1) {
- current.tm_mon--;
- if (current.tm_mon < JAN) {
- current.tm_mon = DEC;
- current.tm_year--;
- }
- current.tm_mday += monthlength(current.tm_mon);
- } else if (current.tm_mday > monthlength(current.tm_mon)) {
- current.tm_mday -= monthlength(current.tm_mon);
- current.tm_mon++;
- if (current.tm_mon > DEC) {
- current.tm_mon = JAN;
- current.tm_year++;
- }
- }
- current.tm_yday = current.tm_mday - 1;
- for (month = 0; month < current.tm_mon; month++) {
- current.tm_yday += monthlength(month);
- }
- if ((current.tm_year < today.tm_year)
- || ((current.tm_year == today.tm_year)
- && (current.tm_yday < today.tm_yday))) {
- from = current;
- to = today;
- } else {
- from = today;
- to = current;
- }
- if (from.tm_year != to.tm_year) {
- for (totdays = 0; from.tm_year < to.tm_year; from.tm_year++)
- totdays += dysize(from.tm_year + 1900);
- }
- totdays += to.tm_yday - from.tm_yday;
- if ((current.tm_year < today.tm_year)
- || ((current.tm_year == today.tm_year)
- && (current.tm_yday < today.tm_yday)))
- totdays = -totdays;
- current.tm_wday =
- ((totdays % 7) + 7 + today.tm_wday) % 7;
- }
-
- /*
- * Compares two sets of year/month/day. Returns -1 if the first is earlier than
- * the second, +1 if later, 0 if they are the same.
- */
- ymd_compare(day0, day1)
- struct tm day0, day1;
- {
- if (day0.tm_year > day1.tm_year) return(1);
- if (day0.tm_year < day1.tm_year) return(-1);
- if (day0.tm_mon > day1.tm_mon) return(1);
- if (day0.tm_mon < day1.tm_mon) return(-1);
- if (day0.tm_mday > day1.tm_mday) return(1);
- if (day0.tm_mday < day1.tm_mday) return(-1);
- return(0);
- }
-
- int
- monthlength(month)
- int month;
- {
- static int monthlengths[] = {31,28,31,30,31,30,31,31,30,31,30,31};
-
- if (month == FEB && (dysize(current.tm_year + 1900) == 366))
- return(29);
- else
- return(monthlengths[month]);
- }
-
- /*
- *
- * Append data from active timeslots to end of "tmp.appointments"
- * file, then copy "tmp.appointments" to "appointments". Note that
- * when we opened the current day we filtered "appointments":
- * all items that applied to the current day were displayed and
- * stored in slots; all others were copied to "tmp.appointments".
- * So by now "tmp.appointments" contains no entries for the
- * current day.
- * As an optimization, if nothing changed in the day then the
- * original appointments file is left unchanged.
- *
- */
-
- close_day()
- {
- int i, j;
- FILE *f;
- struct stat sbuf;
- struct appt_entry *aptr, *optr;
-
- if (read_only || !new_entry) {
- new_entry = 0;
- day_is_open = FALSE;
- return(0);
- }
-
- f = fopen(tmpapts_pathname, "a+");
- if (f == NULL) {
- err_rpt("can't open temp file for appending", NON_FATAL);
- day_is_open = FALSE;
- return(1);
- }
-
- for (i=0; i<N_SLOTS; i++) {
- if (slots[i].first != NULL) {
- aptr = slots[i].first;
- if (put_aentry(f, aptr))
- /* write error */
- break;
- optr = aptr;
- while (aptr = aptr->next) {
- free(optr);
- if (put_aentry(f, aptr))
- /* write error */
- break;
- optr = aptr;
- }
- free(optr);
- }
- }
- if (ferror(f))
- err_rpt("write on temp file failed", FATAL);
- fclose(f);
- new_entry = 0;
- day_is_open = FALSE;
- /* don't rename zero length files */
- stat(tmpapts_pathname, &sbuf);
- if (sbuf.st_size == (off_t) 0)
- return(1);
- xrename(tmpapts_pathname, apts_pathname);
- }
-
- /*
- * get entry from appointments file
- */
- get_aentry(apts_file, appt)
- FILE *apts_file;
- struct appt_entry *appt;
- {
- char *ptr, *str;
- char *fgets(), *index();
- char *incl_ptr, incl_buf[128], wday[3];
- int i, lib;
- struct stat sbuf;
- static FILE *include;
-
- appt->flags = appt->repeat = appt->lookahead = 0;
- appt->sindex = 0;
- appt->next = NULL;
- if (including) {
- if (fgets(inbuf, 512, include) == NULL) {
- /* end of include file - get next entry
- * from main file
- */
- including = 0;
- fclose(include);
- if (fgets(inbuf, 512, apts_file) == NULL)
- return(EOF);
- } else {
- including = 2;
- /* don't modify stuff from include files */
- appt->flags |= READONLY;
- }
- } else
- if (fgets(inbuf, 512, apts_file) == NULL)
- return(EOF);
- ptr = inbuf;
- if (*ptr == '#') {
- if (!strcmp(inbuf, HEADER) && !including) {
- /* first line in file read */
- if (include_old && (First.tm_year < today.tm_year)) {
- /* read in old include file (if it exists) */
- /* prepend directory info */
- sprintf(incl_buf, "%s/.appointments.%02d",
- apts_dir, First.tm_year);
- if (!stat(incl_buf, &sbuf)) {
- if ((include = fopen(incl_buf, "r")) == NULL)
- err_rpt("can't open include file (ignored)", NON_FATAL);
- else
- including = 1;
- }
- }
- } else if (!strncmp(inbuf, "#include", 8)) {
- /* include file */
- if (including)
- err_rpt("include files may not be nested", FATAL);
- incl_ptr = strbuf;
- if ((ptr = index(inbuf, '"')) == NULL)
-
- if ((ptr = index(inbuf, '<')) == NULL) {
- err_rpt("missing '\"' or '<' in include file spec", NON_FATAL);
- return(0);
- } else {
- lib = 1;
- }
- else
- lib = 0;
- ptr++;
- while (*ptr && *ptr != '"' && *ptr != '>')
- *incl_ptr++ = *ptr++;
- if (! *ptr) {
- err_rpt("missing '\"' or '>' in include file spec", NON_FATAL);
- return(0);
- }
- *incl_ptr = '\0';
- if (strbuf[0] == '/')
- /* full pathname provided */
- strcpy(incl_buf, strbuf);
- else
- /* prepend directory info */
- if (lib)
- sprintf(incl_buf, "%s/%s", lib_dir, strbuf);
- else
- sprintf(incl_buf, "%s/%s", apts_dir, strbuf);
- if ((include = fopen(incl_buf, "r")) == NULL)
- err_rpt("can't open include file (ignored)", NON_FATAL);
- else
- including = 1;
- }
- appt->flags |= A_COMMENT;
- return(0);
- }
- while (isspace(*ptr))
- ++ptr;
- if (!*ptr) {
- /* empty line */
- appt->flags |= A_COMMENT;
- return(0);
- }
- if (*ptr == '*') {
- appt->flags |= ALL_YEARS;
- appt->year = START_YEAR;
- ++ptr; /* point to second '*' */
- ++ptr; /* point to space */
- } else {
- appt->year = 0;
- while (isdigit(*ptr)) {
- appt->year *= 10;
- appt->year += *ptr++ - '0';
- }
- /* sanity check */
- if (appt->year < 0) {
- err_rpt("illegal year value (ignored)", NON_FATAL);
- return(1);
- }
- }
- while (isspace(*ptr))
- ++ptr;
- if (*ptr == '*') {
- appt->flags |= ALL_MONTHS;
- appt->month = 0;
- ++ptr;
- } else {
- appt->month = (*ptr - '0') * 10;
- appt->month += *++ptr - '0';
- if (one_based) (appt->month)--;
- /* sanity check */
- if (appt->month < JAN || appt->month > DEC) {
- /*
- sprintf(errbuf, "illegal month value [%d] (ignored)", appt->month);
- err_rpt(errbuf, NON_FATAL);
- */
- err_rpt("illegal month value (ignored)", NON_FATAL);
- return(1);
- }
- }
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- if (*ptr == '*') {
- appt->flags |= ALL_DAYS;
- appt->day = 0;
- appt->repeat = 1;
- ++ptr;
- } else if (isdigit(*ptr)) {
- appt->day = (*ptr - '0') * 10;
- appt->day += *++ptr - '0';
- if (!one_based) (appt->day)++;
- /* sanity check */
- if (appt->day < 1 || appt->day > 31) {
- err_rpt("illegal day value (ignored)", NON_FATAL);
- return(1);
- }
- } else {
- /* check for day names */
- wday[0] = islower(*ptr) ? toupper(*ptr) : *ptr;
- ++ptr;
- wday[1] = islower(*ptr) ? toupper(*ptr) : *ptr;
- wday[2] = '\0';
- i = 0;
- if (!strcmp(wday, dayname[i++]))
- appt->flags |= EVERY_SUN;
- else if (!strcmp(wday, dayname[i++]))
- appt->flags |= EVERY_MON;
- else if (!strcmp(wday, dayname[i++]))
- appt->flags |= EVERY_TUE;
- else if (!strcmp(wday, dayname[i++]))
- appt->flags |= EVERY_WED;
- else if (!strcmp(wday, dayname[i++]))
- appt->flags |= EVERY_THU;
- else if (!strcmp(wday, dayname[i++]))
- appt->flags |= EVERY_FRI;
- else if (!strcmp(wday, dayname[i]))
- appt->flags |= EVERY_SAT;
- else {
- /* sanity check */
- err_rpt("illegal day name (ignored)", NON_FATAL);
- return(1);
- }
- appt->day = 0;
- appt->flags |= REPEAT;
- appt->repeat = ALL_WEEKS; /* default to every week */
- }
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- appt->hour = (*ptr - '0') * 10;
- appt->hour += *++ptr - '0';
- /* sanity check */
- if (appt->hour < 0 || (appt->hour > 23 && appt->hour != 99)) {
- err_rpt("illegal hour value (ignored)", NON_FATAL);
- return(1);
- }
- if ((version2 && appt->hour == 99) || (!version2 && appt->hour == 0))
- appt->flags |= A_NOTE;
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- appt->minute = (*ptr - '0') * 10;
- appt->minute += *++ptr - '0';
- /* sanity check */
- if (appt->minute < 0 || (appt->minute > 59 && appt->minute != 99)) {
- /* minutes currently can only be 00 or 30
- * unless it's a note.
- */
- err_rpt("illegal minute value (ignored)", NON_FATAL);
- return(1);
- }
- if ((appt->flags & A_NOTE) && version2 && appt->minute == 99)
- appt->flags |= MARKED; /* don't show in mon/yr display */
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- appt->arrows = (*ptr - '0') * 10;
- appt->arrows += *++ptr - '0';
- /* sanity check */
- if (appt->arrows < 0 || appt->arrows > N_TSLOTS) {
- err_rpt("illegal arrow value (ignored)", NON_FATAL);
- return(1);
- }
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- /* lookahead and repeat entries are free format, i.e. they */
- /* can occur in either order */
- if (*ptr == '[') {
- appt->flags |= REPEAT;
- if (appt->flags & EVERY_SOMEDAY) {
- if ((appt->repeat = do_wk_repeat(&ptr)) < 0)
- return(1);
- } else {
- if ((appt->repeat = do_repeat(&ptr)) < 0)
- return(1);
- }
- if (*ptr == '<') {
- appt->flags |= LOOKAHEAD;
- if ((appt->lookahead = do_lookahead(&ptr)) < 0)
- return(1);
- }
- if (*ptr == '#') {
- appt->flags |= DELETED;
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- }
- } else if (*ptr == '<') {
- appt->flags |= LOOKAHEAD;
- if ((appt->lookahead = do_lookahead(&ptr)) < 0)
- return(1);
- if (*ptr == '[') {
- appt->flags |= REPEAT;
- if (appt->flags & EVERY_SOMEDAY) {
- if ((appt->repeat = do_wk_repeat(&ptr)) < 0)
- return(1);
- } else {
- if ((appt->repeat = do_repeat(&ptr)) < 0)
- return(1);
- }
- }
- if (*ptr == '#') {
- appt->flags |= DELETED;
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- }
- } else if (*ptr == '#') {
- appt->flags |= DELETED;
- ++ptr;
- while (isspace(*ptr))
- ++ptr;
- }
- str = strbuf;
- while (*ptr && *ptr != '\n')
- *str++ = *ptr++;
- *str = '\0';
- strcpy(appt->str, strbuf);
-
- return(0);
- }
-
- /* parse normal repeated entry field */
- do_repeat(ptr)
- char **ptr;
- {
- int repeat = 0;
-
- while (isdigit(*++*ptr))
- repeat = repeat * 10 + (int)(**ptr - '0');
- if (**ptr != ']') {
- err_rpt("bad entry (ignored)", NON_FATAL);
- return(-1);
- }
- /* sanity check */
- if (repeat < 0) {
- err_rpt("illegal repeat interval (ignored)", NON_FATAL);
- return(-1);
- }
- ++*ptr;
- while (isspace(**ptr))
- ++*ptr;
- return(repeat);
- }
-
- /* parse weekly repeated entry field */
- do_wk_repeat(ptr)
- char **ptr;
- {
- int repeat = 0;
-
- while (*++*ptr != ']') {
- if (**ptr == ',')
- continue; /* get next week */
- if (isdigit(**ptr)) {
- repeat |= 0x1<<(**ptr - '1');
- } else if (**ptr == 'L' || **ptr == 'l') {
- /* last week in month */
- repeat |= LAST_WEEK;
- } else {
- /* format error */
- err_rpt("illegal repeat specification (ignored)", NON_FATAL);
- return(-1);
- }
- }
- /* sanity check */
- if ((unsigned int)repeat > WEEK_LIMIT) {
- err_rpt("illegal weekly repeat (ignored)", NON_FATAL);
- return(-1);
- }
- ++*ptr;
- while (isspace(**ptr))
- ++*ptr;
-
- return(repeat);
- }
-
- /* parse lookahead entry field */
- do_lookahead(ptr)
- char **ptr;
- {
- int lookahead = 0;
-
- while (isdigit(*++*ptr))
- lookahead = lookahead * 10 + (int)(**ptr - '0');
- if (**ptr != '>') {
- err_rpt("bad entry (ignored)", NON_FATAL);
- return(-1);
- }
- /* sanity check */
- if (lookahead < 0) {
- err_rpt("illegal lookahead interval (ignored)", NON_FATAL);
- return(-1);
- }
- ++*ptr;
- while (isspace(**ptr))
- ++*ptr;
- return(lookahead);
- }
-
- /*
- * put entry into appointments file
- */
- put_aentry(apts_file, appt)
- FILE *apts_file;
- struct appt_entry *appt;
- {
- char *to_str();
-
- if (read_only)
- return(0);
-
- if (appt->flags & READONLY)
- /* don't copy include file entries */
- /* (the include directive is copied as a comment) */
- return(0);
- if (appt->flags & A_COMMENT) {
- fputs(inbuf, apts_file);
- return(ferror(apts_file));
- }
- if (appt->flags & ALL_YEARS)
- fputs("** ", apts_file);
- else if (appt->year > 99)
- fprintf(apts_file, "%03d ", appt->year);
- else
- fprintf(apts_file, "%02d ", appt->year);
- if (appt->flags & ALL_MONTHS)
- fputs("** ", apts_file);
- else
- fprintf(apts_file, "%02d ", one_based ? appt->month+1 : appt->month);
- if (appt->flags & ALL_DAYS)
- fputs("** ", apts_file);
- else if (appt->flags & EVERY_SOMEDAY) {
- switch (appt->flags & EVERY_SOMEDAY) {
- case EVERY_SUN:
- fputs("Su ", apts_file);
- break;
- case EVERY_MON:
- fputs("Mo ", apts_file);
- break;
- case EVERY_TUE:
- fputs("Tu ", apts_file);
- break;
- case EVERY_WED:
- fputs("We ", apts_file);
- break;
- case EVERY_THU:
- fputs("Th ", apts_file);
- break;
- case EVERY_FRI:
- fputs("Fr ", apts_file);
- break;
- case EVERY_SAT:
- fputs("Sa ", apts_file);
- break;
- }
- } else
- fprintf(apts_file, "%02d ", one_based ? appt->day : appt->day-1);
- if (appt->flags & A_NOTE) {
- appt->hour = 99;
- appt->minute = 0; /* assume unmarked note */
- }
- if ((appt->flags & MARKED_NOTE) == MARKED_NOTE)
- appt->minute = 99;
- if (!(appt->flags & (ALL_DAYS|DELETED)) && appt->flags & REPEAT) {
- if (appt->flags & EVERY_SOMEDAY)
- fprintf(apts_file, "%02d %02d %02d %s ", appt->hour, appt->minute, appt->arrows, to_str(appt->repeat));
- else
- fprintf(apts_file, "%02d %02d %02d [%d] ", appt->hour, appt->minute, appt->arrows, appt->repeat);
- } else
- fprintf(apts_file, "%02d %02d %02d ", appt->hour, appt->minute, appt->arrows);
-
- if (appt->flags & LOOKAHEAD)
- fprintf(apts_file, "<%d> ", appt->lookahead);
- if (appt->flags & DELETED)
- fprintf(apts_file, "# %s\n", appt->str);
- else
- fprintf(apts_file, "%s\n", appt->str);
-
- /* check for failure (e.g. file system full) */
- return(ferror(apts_file));
- }
-
- char rptstr[10];
-
- /* convert repeat bit map to printable string */
- char *
- to_str(repeat)
- int repeat;
- {
- int i, j = 0;
-
- if (repeat == ALL_WEEKS)
- /* if it's every week, then don't write [] spec */
- rptstr[0] = '\0';
- else {
- rptstr[j++] = '[';
- for (i=0; i<5; i++) {
- if (repeat & (0x1<<i)) {
- rptstr[j++] = i+1 + '0';
- rptstr[j++] = ',';
- }
- }
- if (repeat & LAST_WEEK) {
- rptstr[j++] = 'L';
- rptstr[j++] = ',';
- }
- rptstr[j] = '\0';
- rptstr[--j] = ']';
- }
- return (rptstr);
- }
-
- /*
- * Print today's appointments to stdout or mail (useful if we only have an ASCII
- * terminal connected to our Sun). Invoked by the "-p", "-P" or "-m" options.
- */
- print_apts(level)
- int level;
- {
- int i;
- FILE *output, *popen();
- char cmd[80], *name, *cuserid(), *format_appt();
- struct appt_entry tmp_apt, *sptr;
-
- fix_current_day();
- get_day_appts();
- if (level == 2) {
- if (mailto != NULL) {
- name = mailto;
- } else if ((name = cuserid(NULL)) == NULL) {
- err_rpt("nobody to mail to", FATAL);
- }
- sprintf(cmd, "mail -s \"Appointments for today\" %s", name);
- if ((output = popen(cmd, "w")) == NULL)
- err_rpt("Couldn't pipe to 'mail'", FATAL);
- } else {
- output = stdout;
- }
-
- fprintf(output,"\n\t*** Appointments for %s %s %d, 19%02d ***\n\n",
- daynames[current.tm_wday], monthnames[current.tm_mon],
- current.tm_mday, current.tm_year);
-
- for (i=0; i<N_SLOTS; i++) {
- if (i == n_tslots)
- /* start of notes section */
- fprintf(output,"\n\t\t ===== Notes =====\n");
- if (slots[i].first != NULL && slots[i].count > 0) {
- /* at least one appt here */
- slots[i].cur_appt = slots[i].first;
- do {
- if (level == 3 && ((slots[i].cur_appt->flags & MARKED_NOTE) == MARKED_NOTE))
- continue;
- if (chk_deleted(i))
- continue;
- tmp_apt = *slots[i].cur_appt;
- tmp_apt.year = current.tm_year;
- tmp_apt.month = current.tm_mon;
- tmp_apt.day = current.tm_mday;
- fprintf(output, "%s\n", format_appt(&tmp_apt));
- } while ((slots[i].cur_appt = slots[i].cur_appt->next) != NULL);
- }
- }
- if (findex) {
- /* print out future appointments */
- fprintf(output, "\n\t\t===== Future Reminders =====\n");
- for (i=0; i<findex; i++)
- fprintf(output, "%s\n", format_appt(&future[i]));
- }
- fflush(output);
- if (level == 2)
- pclose(output);
- }
-
- /*
- * Convert from version 1 appts files to version 2 file format.
- */
- ver1to2()
- {
- FILE *oappts, *nappts, *fp;
- struct appt_entry appt;
- int err_flag, save_base;
- char save_file[128];
- struct stat stbuf;
-
- /*
- * The main difference is that the ver 2 files are one-based, i.e
- * days and months start with 1, rather than 0. Another difference
- * is that a hour entry of 99 is used to flag a memo entry, rather
- * than 00. This allows for 24-hour appointments.
- * Version 2 appts files are marked with a special header line
- * defined by the HEADER string (in ct.h). Version 2 files
- * also support a "lookahead" reminder service to remind one
- * in advance of a future appointment.
- * If "save_old" is set, then any appointments for years prior
- * to this one are save in a special file of the form
- * ".appointments.YY", where YY is the year.
- */
-
- if (read_only != 0) {
- err_rpt("appts file is read-only, no conversion done", NON_FATAL);
- return;
- }
-
- /* open files, etc */
- if ((oappts = fopen(apts_pathname, "r")) == NULL) {
- err_rpt("can't open appts file for reading", FATAL);
- /* NOT REACHED */
- }
- if ((nappts = fopen(tmpapts_pathname, "w")) == NULL) {
- err_rpt("can't open temp file for writing", NON_FATAL);
- return;
- }
- /* write new header line */
- fputs(HEADER, nappts);
-
- /* copy existing entries to the new file */
- save_base = one_based;
- while ((err_flag = get_aentry(oappts, &appt)) != EOF) {
- if (err_flag)
- continue; /* ignore badly formatted input */
- if (appt.hour == 0)
- appt.flags |= A_NOTE;
- one_based = 1; /* force new format output */
- if (save_old && !(appt.flags & ALL_YEARS) && (appt.year < today.tm_year)
- && !((appt.flags & REPEAT) && !(appt.flags & EVERY_SOMEDAY))
- && !(appt.flags & A_COMMENT)) {
- /* prepend directory info */
- sprintf(save_file, "%s/.appointments.%02d",
- apts_dir, appt.year);
- if (stat(save_file, &stbuf) && errno == ENOENT) {
- /* new file*/
- if ((fp = fopen(save_file, "w")) == NULL)
- err_rpt("can't open save file, bailing out", FATAL);
- fputs(HEADER, fp);
- fclose(fp);
- }
- if ((fp = fopen(save_file, "a+")) == NULL)
- err_rpt("can't open save file, bailing out", FATAL);
- else {
- if (put_aentry(fp, &appt))
- err_rpt("write to save appt file failed, bailing out", FATAL);
- fclose(fp);
- }
- } else {
- if (put_aentry(nappts, &appt))
- err_rpt("write to new appt file failed, bailing out", FATAL);
- }
- one_based = save_base; /* (maybe) force old format input */
- }
- fclose(oappts);
- fclose(nappts);
- xrename(tmpapts_pathname, apts_pathname);
- one_based = 1;
- version2 = 1;
- }
-
- /*
- * Scan appointments file for outdated appointments and save them to a
- * special file of the form ".appointments.YY", where YY is the year
- * of that appointment.
- */
- create_old_files()
- {
- FILE *oappts, *nappts, *fp;
- struct appt_entry appt;
- int err_flag;
- char save_file[128];
- struct stat stbuf;
-
- if (read_only != 0) {
- err_rpt("appts file is read-only, no conversion done", NON_FATAL);
- return;
- }
-
- /* open files, etc */
- if ((oappts = fopen(apts_pathname, "r")) == NULL) {
- err_rpt("can't open appts file for reading", FATAL);
- /* NOT REACHED */
- }
- if ((nappts = fopen(tmpapts_pathname, "w")) == NULL) {
- err_rpt("can't open temp file for writing", NON_FATAL);
- return;
- }
-
- /* copy existing entries to the tmp file, checking dates */
- while ((err_flag = get_aentry(oappts, &appt)) != EOF) {
- if (err_flag)
- continue; /* ignore badly formatted input */
- if (!(appt.flags & A_COMMENT)
- && !(appt.flags & ALL_YEARS) && (appt.year < today.tm_year)
- && !((appt.flags & REPEAT) && !(appt.flags & EVERY_SOMEDAY))) {
- /* prepend directory info */
- sprintf(save_file, "%s/.appointments.%02d",
- apts_dir, appt.year);
- if (stat(save_file, &stbuf) && errno == ENOENT) {
- /* new file*/
- if ((fp = fopen(save_file, "w")) == NULL)
- err_rpt("can't open save file, bailing out", FATAL);
- fputs(HEADER, fp);
- fclose(fp);
- }
- if ((fp = fopen(save_file, "a+")) == NULL)
- err_rpt("can't open save file, bailing out", FATAL);
- else {
- if (put_aentry(fp, &appt))
- err_rpt("write to save appt file failed, bailing out", FATAL);
- fclose(fp);
- }
- } else {
- if (put_aentry(nappts, &appt))
- err_rpt("write to new appt file failed, bailing out", FATAL);
- }
- }
- fclose(oappts);
- fclose(nappts);
- xrename(tmpapts_pathname, apts_pathname);
- }
-
- /*
- * convert appt entry to ASCII string for display with date, time and msg
- */
- char *
- format_appt(appt)
- struct appt_entry *appt;
- {
- int e_hour, e_minutes, duration;
- struct tm Save;
-
- if (appt->arrows > 0) {
- duration = appt->arrows + 1;
- e_hour = appt->hour + duration/2;
- e_minutes = appt->minute + ((duration%2) * 30);
- } else {
- e_hour = appt->hour;
- e_minutes = appt->minute + 30;
- }
- if (e_minutes == 60) {
- e_minutes = 0;
- ++e_hour;
- }
- /* get day of week */
- Save = current;
- current.tm_year = appt->year;
- current.tm_mon = appt->month;
- current.tm_mday = appt->day;
- fix_current_day();
-
- if (appt->flags & A_NOTE) {
- /* note */
- if (appt->flags & ALL_YEARS)
- sprintf(strbuf,"%3.3s %2d/%02d -- %s",
- daynames[current.tm_wday], appt->month+1,
- appt->day, appt->str);
- else if (appt->year > 99)
- sprintf(strbuf,"%3.3s %2d/%02d/%02d -- %s",
- daynames[current.tm_wday], appt->month+1,
- appt->day, appt->year-100, appt->str);
- else
- sprintf(strbuf,"%3.3s %2d/%02d/%02d -- %s",
- daynames[current.tm_wday], appt->month+1,
- appt->day, appt->year, appt->str);
- } else
- /* standard appointment */
- sprintf(strbuf,"%3.3s %2d/%02d/%02d -- %2d:%02d to %2d:%02d %s",
- daynames[current.tm_wday], appt->month+1,
- appt->day, appt->year, appt->hour, appt->minute,
- e_hour, e_minutes, appt->str);
-
- current = Save;
- return(strbuf);
- }
-
- /*
- * convert appt entry to ASCII string for display with time and msg
- */
- char *
- format_appt_nd(appt)
- struct appt_entry *appt;
- {
- int e_hour, e_minutes, duration;
- struct tm Save;
-
- if (appt->arrows > 0) {
- duration = appt->arrows + 1;
- e_hour = appt->hour + duration/2;
- e_minutes = appt->minute + ((duration%2) * 30);
- } else {
- e_hour = appt->hour;
- e_minutes = appt->minute + 30;
- }
- if (e_minutes == 60) {
- e_minutes = 0;
- ++e_hour;
- }
-
- if (appt->flags & A_NOTE) {
- /* note */
- sprintf(strbuf,"%s", appt->str);
- } else
- /* standard appointment */
- sprintf(strbuf,"%2d:%02d to %2d:%02d %s",
- appt->hour, appt->minute, e_hour, e_minutes, appt->str);
-
- return(strbuf);
- }
-
- /*
- * parse the date on the given tring and reset the "current"
- * date to reflect that date. The date may take the form of a
- * day name (e.g. Tu, Tue, Tuesday) or a date in m/d/y format
- * where the month and/or year may be missing (e.g. 27 = 27th
- * of this month, 8/27 = August 27 of this year, 8/27/89 =
- * August 27 of 1989. If 'cmdline' is true, then the string
- * came from the command line '-d' option.
- */
- int
- parse_date(str, cmdline)
- char *str;
- int cmdline;
- {
- char c[4];
- int i, dow = -1, m = -1, d = -1, y = -1;
-
- if (isdigit(*str)) {
- /* must be a m/d/y date */
- /* assume it's a month first */
- m = *str++ - '0';
- if (isdigit(*str))
- m = m*10 + *str++ - '0';
- if (!*str) {
- /* no more chars => day only */
- d = m;
- m = -1;
- } else if (*str++ != '/') {
- if (cmdline)
- err_rpt("badly formed date for -d option (ignored)", NON_FATAL);
- else
- err_rpt("badly formed date - please reenter", NON_FATAL);
- return(1);
- } else {
- d = *str++ - '0';
- if (isdigit(*str))
- d = d*10 + *str++ - '0';
- if (*str++ == '/') {
- /* year also specified */
- y = *str++ - '0';
- if (isdigit(*str)) {
- y = y*10 + *str++ - '0';
- if (*str && isdigit(*str))
- y = y*10 + *str - '0';
- }
- }
- }
- if (y > 0)
- current.tm_year = y;
- if (m > 0)
- current.tm_mon = m - 1;
- if (d > 0)
- current.tm_mday = d;
- fix_current_day();
- } else {
- /* day of week */
- /* check for day names */
- c[0] = islower(*str) ? toupper(*str) : *str;
- ++str;
- c[1] = islower(*str) ? toupper(*str) : *str;
- c[2] = '\0';
- for (i=0; i<7; i++) {
- if (!strcmp(c, dayname[i])) {
- dow = i;
- break;
- }
- }
- if (dow >= 0) {
- /* match found */
- current.tm_mday += dow - current.tm_wday;
- fix_current_day();
- } else {
- if (cmdline)
- err_rpt("badly formed date for -d option (ignored)", NON_FATAL);
- else
- err_rpt("badly formed date - please reenter", NON_FATAL);
- return(1);
- }
- }
- return(0);
- }
-
- #ifndef NO_PRINTER
- /*
- * Print to Postscript compatable printer. If we are displaying
- * the day or week page, then create a raster file of the canvas and
- * feed it to a raster->ps filter (sun2ps). If on a month page, then
- * print a pretty month calendar with appts written in (as best
- * can be).
- */
- print_calendar(file_type)
- int file_type;
- {
- Pixrect *save_pr;
- char prntcmd[64];
- int type = RT_STANDARD;
- int copy_flag = TRUE;
- Rect *rect;
- struct pr_prpos where;
- char buf[128], *cuserid();
- FILE *fp, *pfp;
-
- lock_cursors();
- working(TRUE);
- sprintf(buf, "Appointments file \"%s\" printed for %s on %s", apts_pathname, cuserid(NULL), todays_date);
- if (mainsw_state != DISPLAYING_MONTH) {
- if ((fp = fopen(rasfile, "w")) != NULL) {
- rect = (Rect *) window_get(canvas, WIN_RECT);
- save_pr = mem_create(rect->r_width, rect->r_height+3*sfont->pf_defaultsize.y, 1);
- pr_rop(save_pr,0,0,rect->r_width-3,rect->r_height,PIX_SRC,main_pixwin->pw_prretained,0,0);
- where.pr = save_pr;
- where.pos.x = 6 * font->pf_defaultsize.x;
- where.pos.y = rect->r_height + 2*sfont->pf_defaultsize.y;
- pf_text(where, PIX_SRC, sfont, buf);
- pr_dump(save_pr, fp, NULL, type, copy_flag);
- fclose(fp);
- if (file_type == PR_POSTSCRIPT) {
- if ((pfp = fopen(psfile, "w")) != NULL) {
- fp = fopen(rasfile, "r");
- /* ras2ps closes the files that
- * we opened here.
- */
- ras2ps(fp, pfp);
- sprintf(prntcmd, "%s %s", printer, psfile);
- system(prntcmd);
- unlink(psfile);
- } else
- err_rpt("can't open tmp ps file", NON_FATAL);
- } else {
- sprintf(prntcmd, "%s %s", printer, rasfile);
- system(prntcmd);
- }
- pr_destroy(save_pr);
- unlink(rasfile);
- } else
- err_rpt("can't open tmp raster file", NON_FATAL);
- } else if (mainsw_state == DISPLAYING_MONTH) {
- if (file_type != PR_POSTSCRIPT) {
- err_rpt("only PostScript output available for month printout", NON_FATAL);
- } else {
- if ((pfp = fopen(psfile, "w")) != NULL) {
- print_month(pfp);
- fclose(pfp);
- sprintf(prntcmd, "%s %s", printer, psfile);
- system(prntcmd);
- unlink(psfile);
- } else
- err_rpt("can't open tmp ps file", NON_FATAL);
- }
- }
- working(FALSE);
- unlock_cursors();
- }
- #endif /* NO_PRINTER */
-
- /* set error logging flag */
- err2console(state)
- int state;
- {
- /*
- * if TRUE, forces error messages to the console, even
- * if the base frame is running
- */
- log_to_console = state;
- }
-
- /*
- * Error reporting. Try first to put message in a popup frame, then
- * the console, then stderr as a last resort.
- */
- err_rpt(errstr, fatal_flag)
- char *errstr;
- int fatal_flag;
- {
- FILE *f;
- int closed;
-
- closed = (int) window_get(frame, FRAME_CLOSED);
- if (frame && !log_to_console && !closed) {
- /* base frame exists */
- create_prompt_frame(errstr, FALSE);
- (void) window_loop(prompt_frame);
- window_set(prompt_frame, WIN_SHOW, FALSE, 0);
- } else if ((f=fopen("/dev/console", "w")) != NULL) {
- fprintf(f, "%s: %s\n", progname, errstr);
- fclose(f);
- } else
- fprintf(stderr, "%s: %s\n", progname, errstr);
- if (fatal_flag)
- exit(1);
- }
-
- /* Clean-up */
- cleanup()
- {
- if (day_is_open)
- close_day();
-
- /* create outdated include files (if necessary) */
- if (save_old)
- create_old_files();
-
- /* delete tmp file */
- if (access(tmpapts_pathname, R_OK) == 0 && unlink(tmpapts_pathname) < 0)
- perror(tmpapts_pathname);
- }
-
- char sysbuf[512];
-
- /* Rename files, copying if necessary */
- xrename(from, to)
- char *from, *to;
- {
- if (rename(from, to) == -1) {
- /* rename sys call fialed, try doing a copy */
- sprintf(sysbuf, "cp %s %s", from, to);
- if (system(sysbuf) != 0)
- err_rpt("couldn't rename/copy tmp file", NON_FATAL);
- }
- }
-