v13i003: xcal, Part03/04
Peter Collinson
pc at hillside.co.uk
Mon May 13 06:26:19 AEST 1991
Submitted-by: Peter Collinson <pc at hillside.co.uk>
Posting-number: Volume 13, Issue 3
Archive-name: xcal/part03
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# xcal_popup.c
# xcal_alarm.c
# xcal_cal.man
# xcal_edit.c
# This archive created: Wed May 8 09:14:08 1991
export PATH; PATH=/bin:$PATH
echo shar: extracting "'xcal_popup.c'" '(8790 characters)'
if test -f 'xcal_popup.c'
then
echo shar: will not over-write existing file "'xcal_popup.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'xcal_popup.c'
X#ifndef lint
Xstatic char *sccsid = "@(#)xcal_popup.c 3.5 (Hillside Systems) 1/16/91";
Xstatic char *copyright = "@(#)Copyright 1989,1990 Peter Collinson, Hillside Systems";
X#endif /* lint */
X/***
X
X* module name:
X xcal_popup.c
X* function:
X Deal with various popups for xcal
X There are two main ones:
X a) the centre button causes a popup date selection popup
X b) the right button causes an exit popup
X* history:
X Written November 1989
X Peter Collinson
X Hillside Systems
X* (C) Copyright: 1989 Hillside Systems/Peter Collinson
X
X For full permissions and copyright notice - see xcal.c
X***/
X#include <stdio.h>
X#include <ctype.h>
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/Shell.h>
X#include <X11/Xaw/Label.h>
X#include <X11/Xaw/Dialog.h>
X#include <X11/Xaw/AsciiText.h>
X#include "xcal.h"
X
Xstatic void AskDialog();
Xstatic void NoCal();
Xstatic void YesCal();
Xstatic char *DateParse();
Xstatic int MonScan();
Xstatic void LeaveDialog();
Xstatic void NoLeave();
Xstatic void YesLeave();
Xstatic void NoEdit();
X
X/*
X * This routine deals with most of the work to create
X * a dialog popup, it is passed a function which is called
X * to create the dialog box
X *
X * The widget here is used for positioning, these popups are
X * always children of the toplevel widget
X */
Xvoid
XDialogPopup(w, fn, arg)
X Widget w;
X void (*fn)();
X caddr_t arg;
X{
X Widget pop;
X Arg args[5];
X Position x,y;
X Position nx, ny;
X Dimension width, height, border;
X
X /*
X * Get the position of the toplevel so we can
X * position the dialog box properly
X */
X XtSetArg(args[0], XtNwidth, &width);
X XtSetArg(args[1], XtNheight, &height);
X XtGetValues(w, args, 2);
X XtTranslateCoords(w, (Position)(width/2),
X (Position)(height/2), &x, &y);
X
X /*
X * Create a popup to hold the dialog
X */
X XtSetArg(args[0], XtNallowShellResize, True);
X XtSetArg(args[1], XtNinput, True);
X XtSetArg(args[2], XtNx, x);
X XtSetArg(args[3], XtNy, y);
X XtSetArg(args[4], XtNsaveUnder, TRUE);
X pop = XtCreatePopupShell("question", transientShellWidgetClass, toplevel, args, 5);
X
X /*
X * Set up the dialog
X */
X (*fn)(pop, arg);
X
X XtRealizeWidget(pop);
X
X /*
X * We can now worry if this box is actually off the screen
X */
X XtSetArg(args[0], XtNwidth, &width);
X XtSetArg(args[1], XtNheight, &height);
X XtSetArg(args[2], XtNborderWidth, &border);
X XtGetValues(pop, args, 3);
X
X border <<= 1;
X XtTranslateCoords(pop, (Position)0, (Position)0, &nx, &ny);
X
X if ((nx + width + border) > WidthOfScreen(XtScreen(toplevel)))
X nx = WidthOfScreen(XtScreen(toplevel)) - width - border;
X else nx = x;
X
X if ((ny + height + border) > HeightOfScreen(XtScreen(toplevel)))
X ny = HeightOfScreen(XtScreen(toplevel)) - height - border;
X else ny = y;
X
X if (nx != x || ny != y)
X { XtSetArg(args[0], XtNx, nx);
X XtSetArg(args[1], XtNy, ny);
X XtSetValues(pop, args, 2);
X }
X XtPopup(pop, XtGrabNone);
X}
X
X/************************************************************************/
X/* */
X/* */
X/* Deals with middle button presses - ask for a date */
X/* */
X/* */
X/************************************************************************/
X
X/*
X * SetDate - ask for a date and start a calendar
X * This is an action routine
X */
X/* ARGSUSED */
Xvoid
XSetDate(w, event, params, numb)
X Widget w;
X XEvent *event;
X String *params;
X Cardinal *numb;
X{
X DialogPopup(toplevel, AskDialog, NULL);
X}
X
X/* ARGSUSED */
Xstatic void
XAskDialog(pop, noop)
X Widget pop;
X Cardinal noop;
X{
X Widget dia;
X Arg args[2];
X WidgetList children; /* which is Widget children[] */
X Cardinal num_children;
X int i;
X
X /* Take from args: "Enter mm yyyy?" */
X XtSetArg(args[0], XtNvalue, "");
X dia = XtCreateManagedWidget("newdate", dialogWidgetClass, pop, args, 1);
X XawDialogAddButton(dia, "ok", YesCal, dia);
X XawDialogAddButton(dia, "cancel", NoCal, pop);
X /*
X * I would like to add CR translations to the text box
X * the only way to get the widget seems to be to use
X * an R4 feature to get the WidgetList
X */
X XtSetArg(args[0], XtNchildren, &children);
X XtSetArg(args[1], XtNnumChildren, &num_children);
X XtGetValues(dia, (ArgList)args, 2);
X for (i = 0; i < num_children; i++)
X { if (XtClass(children[i]) == asciiTextWidgetClass)
X { /* Bingo */
X XtOverrideTranslations(
X children[i],
X XtParseTranslationTable("<Key>Return: SetDateAction()")
X );
X
X }
X else
X if (XtClass(children[i]) == labelWidgetClass)
X { XtSetArg(args[0], XtNresizable, True);
X XtSetValues(children[i], args, 1);
X }
X }
X
X}
X
X/*
X * No we don't want a specified date
X * Closure here is the pop shell
X */
X/* ARGSUSED */
Xstatic void
XNoCal(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X XtDestroyWidget((Widget)closure);
X}
X
X/*
X * Yes we do want a specified date
X * Closure here is the dialog widget
X */
X/* ARGSUSED */
Xstatic void
XYesCal(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X Widget dia;
X Arg args[2];
X Date wanted;
X char *errstr;
X
X dia = (Widget)closure;
X /*
X * Parse the string
X */
X if (errstr = DateParse(XawDialogGetValueString(dia), &wanted))
X { /* insert an error message in the widget */
X XtSetArg(args[0], XtNlabel, errstr);
X XtSetValues(dia, args, 1);
X XBell(XtDisplay(toplevel), 0);
X return;
X }
X XtDestroyWidget(XtParent(dia));
X NewMonthStrip(&wanted);
X}
X
X/*
X * Action mapped to by CR in the dialog
X */
X/* ARGSUSED */
Xvoid
XTextCal(w, event, params, numb)
X Widget w;
X XEvent *event;
X String *params;
X Cardinal *numb;
X{
X YesCal(w, (caddr_t)XtParent(w), 0); /* parent of text widget is the */
X /* dialog box */
X}
X
X/*
X * Parse a date string
X */
Xstatic char *
XDateParse(str, da)
X register char *str;
X Date *da;
X{
X register char *wk;
X int lastc;
X int mo;
X
X *da = today;
X
X wk = str;
X while (isspace(*wk)) wk++;
X if (*wk == '\0')
X return("No data found");
X str = wk;
X if (isdigit(*str))
X { while (isdigit(*str))
X str++;
X lastc = *str;
X *str++ = '\0';
X mo = atoi(wk);
X if (mo < 1 || mo > 12)
X return("Illegal month number");
X da->month = mo - 1;
X }
X else
X if (isalpha(*str))
X { /* be kind - allow month names */
X while (isalpha(*str))
X { if (isupper(*str))
X *str = tolower(*str);
X str++;
X }
X lastc = *str;
X *str++ = '\0';
X mo = MonScan(wk);
X if (mo < 0)
X return("Cannot find month name");
X da->month = mo;
X }
X if (lastc)
X { wk = str;
X while(isspace(*wk))
X wk++;
X str = wk;
X if (*str)
X da->year = atoi(wk);
X }
X return(NULL);
X}
X
X/*
X * Given a string look in our database for a number
X */
Xstatic int
XMonScan(monstr)
Xchar *monstr;
X{
X char *a, *b;
X int ca, cb;
X int mon;
X
X for (mon = 0; mon < 12; mon++)
X for (a = monstr, b = appResources.mon[mon]; ;)
X { ca = *a++;
X if(ca == '\0')
X return(mon);
X if (isupper(ca))
X ca = tolower(ca);
X cb = *b++;
X if (cb == '\0')
X break;
X if (isupper(cb))
X cb = tolower(cb);
X if (ca != cb)
X break;
X }
X return(-1);
X}
X
X/************************************************************************/
X/* */
X/* */
X/* Deals with right button presses - exit */
X/* */
X/* */
X/************************************************************************/
X/*
X * Get out - possibly
X */
X/* ARGSUSED */
Xvoid
XAskLeave(w, event, params, numb)
X Widget w;
X XEvent *event;
X String *params;
X Cardinal *numb;
X{
X
X DialogPopup(toplevel, LeaveDialog, NULL);
X}
X
X/* ARGSUSED */
Xstatic void
XLeaveDialog(pop, noop)
X Widget pop;
X Cardinal noop;
X{ Widget di;
X
X /* Take "Really exit? from resources */
X di = XtCreateManagedWidget("exit", dialogWidgetClass, pop, NULL, 0);
X XawDialogAddButton(di, "yes", YesLeave, 0);
X XawDialogAddButton(di, "no", NoLeave, pop);
X}
X
X/* ARGSUSED */
Xstatic void
XYesLeave(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X Leave(0);
X}
X
X/* ARGSUSED */
Xstatic void
XNoLeave(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X XtDestroyWidget((Widget)closure);
X}
X
X/************************************************************************/
X/* */
X/* */
X/* Deal with an attempt to double edit some data */
X/* */
X/* */
X/************************************************************************/
X
X
Xvoid
XNoEditIsPossible(w, da)
X Widget w;
X Date *da;
X{
X static char errmsg[32];
X
X (void) sprintf(errmsg, "Already editing %d %s %d", da->day, appResources.mon[da->month], da->year);
X
X DialogPopup(w, NoEdit, errmsg);
X
X}
X
Xvoid
XNoDayEditIsPossible(w, day)
X Widget w;
X Cardinal day;
X{
X static char errmsg[32];
X
X (void) sprintf(errmsg, "Already editing %s", appResources.day[day]);
X
X DialogPopup(w, NoEdit, errmsg);
X
X}
X
Xstatic void
XNoEdit(pop, errmsg)
X Widget pop;
X String errmsg;
X{
X Arg args[2];
X Widget dia;
X
X XtSetArg(args[0], XtNlabel, errmsg);
X dia = XtCreateManagedWidget("noedit", dialogWidgetClass, pop, args, 1);
X XawDialogAddButton(dia, "ok", NoCal, pop);
X}
SHAR_EOF
if test 8790 -ne "`wc -c < 'xcal_popup.c'`"
then
echo shar: error transmitting "'xcal_popup.c'" '(should have been 8790 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcal_alarm.c'" '(16260 characters)'
if test -f 'xcal_alarm.c'
then
echo shar: will not over-write existing file "'xcal_alarm.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'xcal_alarm.c'
X#ifndef lint
Xstatic char *sccsid = "@(#)xcal_alarm.c 1.13 (Hillside Systems) 1/16/91";
Xstatic char *copyright = "@(#)Copyright 1989/1990 Mark Majhor, Peter Collinson";
X#endif /* lint */
X/***
X
X* module name:
X xcal_alarm.c
X* function:
X Deal with editable days
X This is derived from xcalendar's view of how to store things
X* history:
X Original idea and code from
X Mark Majhor, Sequent written August 1990, received Sept 1990
X I have reworked most of the code and algorithms
X Peter Collinson
X Hillside Systems
X
X* (C) Copyright: 1989/1990 Hillside Systems/Peter Collinson/Mark Majhor
X
X For full permissions and copyright notice - see xcal.c
X
X***/
X#include <X11/IntrinsicP.h> /* for toolkit stuff */
X#include <X11/Intrinsic.h>
X#include <X11/Xos.h>
X#include <X11/StringDefs.h> /* for useful atom names */
X#include <X11/Shell.h>
X#include <X11/Xaw/AsciiText.h>
X#include <X11/Xaw/Text.h>
X#include <X11/Xaw/Command.h>
X#include <X11/Xaw/Label.h>
X#include <X11/Xaw/Form.h>
X#include <X11/Xaw/Paned.h>
X#include <stdio.h> /* for printing error messages */
X#include <ctype.h>
X#include <sys/stat.h> /* for stat() */
X#include <pwd.h> /* for getting username */
X#include <errno.h>
X#include "xcal.h"
X
X#ifndef wordBreak
X#define wordBreak 0x01
X#define scrollVertical 0x02
X#endif
X
Xstatic char *LocalMapStem;
Xstatic char *TodayFile;
Xstatic Alarm head;
Xstatic int *countDown;
Xstatic int countDownCt;
X
Xstatic XtCallbackRec callbacks[] = {
X {NULL, NULL},
X {NULL, NULL}
X};
X
X#define dprintf if (appResources.alarmScan) printf
X
X#define MINUTES(hr, mn) ((hr)*60 + (mn))
X
X/*
X * Local routines
X */
Xstatic void AlarmScan();
Xstatic void FreeAlarmList();
Xstatic void setCall();
Xstatic void beep();
Xstatic void AddAlarm();
Xstatic void DisplayAlarmWindow();
Xstatic void DestroyAlarm();
Xstatic void HoldAlarm();
Xstatic void AutoDestroy();
Xstatic XtTimerCallbackProc AlarmEvent();
Xstatic XtTimerCallbackProc ClockTick();
Xstatic int readDataLine();
X
X/*
X * Initialise variables for the alarm mechanism
X */
Xvoid
XInitAlarms()
X{
X register char *str;
X register char *wk;
X register ct;
X register int *p;
X char *XtMalloc();
X
X if (appResources.alarms == False)
X { dprintf("Alarms not enabled\n");
X return;
X }
X dprintf("Alarms on\n");
X /*
X * Interpret the countDown string established
X * by user - turn this into a vector
X * countDown -> points to a vector of integers
X * indicating the number of mins each alarm will be set
X * countDownCt - the number of integers in the vector
X */
X if (str = appResources.countdown)
X { for (wk = str, ct = 0; *wk; wk++)
X if (*wk == ',')
X ct++;
X ct++; /* no of things to store */
X
X countDown = (int *)XtMalloc(sizeof(int)*(ct+2));
X if (countDown == (int *)0)
X Fatal("Error allocating memory\n");
X
X p = countDown;
X while (*str)
X if (!isdigit(*str))
X str++;
X else break;
X while (*str)
X { *p = 0;
X ct = 0;
X while (isdigit(*str))
X ct = ct*10 + *str++ - '0';
X *p++ = ct;
X countDownCt++;
X while (*str && !isdigit(*str))
X str++;
X }
X }
X if (appResources.update)
X ClockTick(0, 0);
X else AlarmFilePoll(0);
X}
X
X
X/*
X * clock_tic is polled every minute (update) to see if
X * the data file has altered - if so then a new data list is
X * built
X */
Xstatic XtTimerCallbackProc
XClockTick(client_data, id)
X caddr_t client_data;
X XtIntervalId *id;
X{
X int secs = appResources.update;
X time_t ti;
X struct tm *tm;
X
X dprintf("ClockTick\n");
X
X ti = time(0);
X tm = localtime(&ti);
X
X /* syncronise on the clock if this makes sense */
X if (secs && 60%secs == 0 && tm->tm_sec%secs)
X secs -= tm->tm_sec%secs;
X
X /* install a new timer */
X (void) XtAddTimeOut(secs * 1000, ClockTick, (caddr_t) NULL);
X
X AlarmFilePoll(tm);
X MemoPoll();
X}
X
Xvoid
XAlarmFilePoll(tm)
X struct tm *tm;
X{
X time_t ti;
X int files;
X char *home;
X char buf[256];
X char *getenv();
X
X if (appResources.alarms == False)
X return;
X
X if (tm == NULL)
X { ti = time(0);
X tm = localtime(&ti);
X }
X /*
X * Create the name of the data file
X * in a cache to save energy
X */
X if (LocalMapStem == NULL || (tm->tm_hour == 0 && tm->tm_min == 0))
X { home = getenv("HOME");
X if (home == NULL)
X { /* should do things with password files */
X /* but for now we will simply die */
X Fatal("Xcal needs HOME defined in the environment");
X }
X
X if (appResources.calCompat == False)
X { (void) sprintf(buf, "%s/%s/xy%d/xc%d%s%d",
X home, appResources.directory,
X tm->tm_year + 1900, tm->tm_mday,
X appResources.smon[tm->tm_mon],
X tm->tm_year + 1900);
X }
X else
X { (void) sprintf(buf, "%s/%s/xc%d%s%d",
X home, appResources.directory,
X tm->tm_mday, appResources.smon[tm->tm_mon],
X tm->tm_year + 1900);
X }
X if (LocalMapStem)
X XtFree(LocalMapStem);
X LocalMapStem = XtNewString(buf);
X dprintf("Todays Daily Filename = %s\n", LocalMapStem);
X
X if (TodayFile)
X XtFree(TodayFile);
X
X TodayFile = MakeWeeklyName(today.wday);
X }
X
X files = 0;
X /*
X * check for file existence
X */
X if (access(LocalMapStem, F_OK) == 0)
X files = 1;
X if (access(TodayFile, F_OK) == 0)
X files |= 2;
X
X FreeAlarmList();
X
X if (files)
X { if (files&1)
X AlarmScan(LocalMapStem, tm, MINUTES(tm->tm_hour, tm->tm_min));
X if (files&2)
X AlarmScan(TodayFile, tm, MINUTES(tm->tm_hour, tm->tm_min));
X }
X else
X dprintf("No files to scan");
X
X UpdateMemo();
X}
X
Xstatic void
XAlarmScan(file, tm, mnow)
X String file;
X struct tm *tm;
X int mnow;
X{
X FILE *fp;
X char hrstr[16];
X char remline[256];
X char *rem;
X int hr, mn;
X Boolean isAction;
X
X
X dprintf("Scanning data file %s\n", file);
X
X if ((fp = fopen(file, "r")) == NULL)
X { fprintf(stderr, "Unexpected failure to open: %s\n", file);
X exit(1);
X }
X
X while (readDataLine(fp, &hr, &mn, hrstr, remline))
X { /* see if we have an action string to do */
X isAction = False;
X rem = remline;
X if (*rem == '!')
X { isAction = True;
X rem++;
X while (*rem == ' ' || *rem == '\t')
X { if (*rem == '\0')
X goto abort;
X rem++;
X }
X }
X else
X if (strncmp(remline, "%cron", 5) == 0)
X { isAction = True;
X rem += 5;
X while (*rem == ' ' || *rem == '\t')
X { if (*rem == '\0')
X goto abort;
X rem++;
X }
X }
X AddAlarm(mnow, isAction, hr, mn, hrstr, rem);
Xabort:
X ;
X }
X (void) fclose(fp);
X
X /*
X * if we have a timeout - then set up an alarm for it
X */
X if (head.next)
X setCall(tm, mnow);
X}
X
X/*
X * the idea here is to generate a sorted event
X * list - one element for each event
X * we will discard anything that has already happened
X */
Xstatic void
XAddAlarm(mnow, exec, hr, mn, hrstr, rem)
X int mnow;
X Boolean exec;
X int hr;
X int mn;
X char *hrstr;
X char *rem;
X{
X
X Alarm *al, *prev, *new;
X char *XtMalloc();
X int al_hr, al_mn, mm;
X int loop;
X int zero = 0;
X int *p;
X
X if (exec || countDownCt == 0)
X { loop = 1;
X p = &zero;
X }
X else
X { loop = countDownCt;
X p = countDown;
X }
X
X for (;loop--;p++)
X {
X al_hr = hr;
X al_mn = mn;
X if (*p)
X { al_mn -= *p;
X if (al_mn < 0)
X { al_mn += 60;
X al_hr--;
X if (al_hr < 0)
X continue;
X }
X }
X if ((mm = MINUTES(al_hr, al_mn)) < mnow)
X continue;
X
X new = (Alarm *) XtMalloc(sizeof(Alarm));
X if (new == NULL)
X Fatal("Error allocating alarm memory\n");
X new->alarm = XtNewString(hrstr);
X new->what = XtNewString(rem);
X new->alarm_mm = mm;
X new->alarm_state = *p;
X new->isAction = exec;
X new->next = NULL;
X
X /* now insert into correct place in List */
X if (head.next == NULL)
X { head.next = new;
X dprintf("%s - %s; alarm at %02d:%02d\n",
X hrstr, rem, al_hr, al_mn);
X }
X else
X { for (prev = &head, al = head.next; al; prev = al, al = prev->next)
X if (mm < al->alarm_mm)
X break;
X prev->next = new;
X new->next = al;
X dprintf("%s - %s; alarm at %02d:%02d\n",
X hrstr, rem, al_hr, al_mn);
X }
X }
X}
X
X/*
X * read a line looking for a time spec and some data
X * return 1 if found
X * return 0 at end
X * Time spec is: hhmm hmm
X * hh:mm hh.mm
X * h:mm h.mm
X * all above may be optionally followed by:
X * A a AM am Am aM P p PM pm Pm pM
X * the string is terminated by a space or a tab
X */
Xstatic int
XreadDataLine(fin, hrp, minp, timestr, remline)
X FILE *fin;
X int *hrp;
X int *minp;
X char *timestr;
X char *remline;
X{
X register enum readState
X { Ignore, Hr1, Hr2, HrSep,
X Mn1, Mn2, AmPm, LoseM,
X LookSp, LoseSp, Store, AllDone
X } state;
X register int c = 0;
X int hr = 0, mn = 0;
X char *destp;
X
X if (feof(fin))
X return 0;
X
X state = Hr1;
X
X while (state != AllDone)
X { if ((c = getc(fin)) == EOF)
X { if (state == Store)
X break;
X return 0;
X }
X switch (state)
X {
X case Ignore:
X if (c == '\n')
X state = Hr1;
X continue;
X case Hr1:
X destp = timestr;
X if (isdigit(c))
X { hr = c - '0';
X mn = 0;
X destp = timestr;
X *destp = '\0';
X state = Hr2;
X break;
X }
X state = (c == '\n' ? Hr1 : Ignore);
X continue;
X case Hr2:
X if (isdigit(c))
X { hr = hr * 10 + c - '0';
X state = HrSep;
X break;
X }
X /* Falls through to .. */
X case HrSep:
X if (c == ':' || c == '.')
X { state = Mn1;
X break;
X }
X /* Falls through to .. */
X case Mn1:
X if (isdigit(c))
X { mn = c - '0';
X state = Mn2;
X break;
X }
X /* Falls through to .. */
X case Mn2:
X if (isdigit(c))
X { mn = mn * 10 + c - '0';
X state = AmPm;
X break;
X }
X else
X if (state == Mn2)
X { state = (c == '\n' ? Hr1 : Ignore);
X continue;
X }
X /* Falls through to .. */
X case AmPm:
X if (c == 'a' || c == 'A')
X { if (hr == 12)
X hr = 0;
X state = LoseM;
X break;
X }
X else
X if (c == 'p' || c == 'P')
X { if (hr < 12)
X hr += 12;
X state = LoseM;
X break;
X }
X /* Falls through to .. */
X case LoseM:
X if (c == 'M' || c == 'm')
X { state = LookSp;
X break;
X }
X /* Falls through to .. */
X case LookSp:
X if (c == ' ' || c == '\t')
X { state = LoseSp;
X if (hr >= 24 || mn >= 60)
X state = Ignore;
X destp = remline;
X *destp = '\0';
X continue;
X }
X else
X { state = (c == '\n' ? Hr1 : Ignore);
X continue;
X }
X break;
X case LoseSp:
X if (c == ' ' || c == '\t')
X continue;
X state = Store;
X /* Falls through to .. */
X case Store:
X if (c == '\n')
X { state = AllDone;
X continue;
X }
X break;
X }
X *destp++ = c;
X *destp = '\0';
X }
X *hrp = hr;
X *minp = mn;
X return 1;
X}
X
X/*
X * set up the timeout for the next event
X */
Xstatic void
XsetCall(tm, mnow)
X struct tm *tm;
X int mnow;
X{
X Alarm *sc;
X int togo;
X
X for (sc = head.next; sc; sc = sc->next)
X { togo = sc->alarm_mm - mnow;
X if (togo <= 0)
X continue;
X appResources.interval_id = XtAddTimeOut(togo*60*1000 - tm->tm_sec*1000,
X AlarmEvent, (caddr_t) NULL);
X dprintf("Alarm in %d mins\n", togo);
X break;
X }
X}
X
X
Xstatic XtTimerCallbackProc
XAlarmEvent(client_data, id)
X caddr_t client_data;
X XtIntervalId *id;
X{
X int tnow;
X long ti;
X struct tm *tm;
X Alarm *al, *prev;
X char buf[255];
X
X ti = time(0);
X tm = localtime(&ti);
X tnow = MINUTES(tm->tm_hour, tm->tm_min);
X
X dprintf("Alarm %d:%02d\n", tm->tm_hour, tm->tm_min);
X
X for (prev = &head, al = head.next; al; prev = al, al = al->next)
X {
X if (tnow == al->alarm_mm)
X { if (appResources.cmd != NULL)
X { (void) sprintf(buf, "%s %s &", appResources.cmd, al->what);
X system(buf);
X }
X if (al->isAction == False)
X { DisplayAlarmWindow(al->alarm_state, al->alarm, al->what);
X beep(); /* notify the user */
X }
X else
X system(al->what);
X
X }
X
X if (al->alarm_mm <= tnow)
X { prev->next = al->next;
X XtFree(al->alarm);
X XtFree(al->what);
X XtFree(al);
X al = prev;
X }
X else
X break;
X }
X setCall(tm, tnow);
X}
X
Xstatic void
Xbeep()
X{
X register Display *dpy = XtDisplay(toplevel);
X int i;
X
X for (i = 0; i < appResources.nbeeps; i++)
X { XBell(dpy, appResources.volume);
X sleep(1);
X }
X}
X
Xstatic void
XFreeAlarmList()
X{
X register Alarm *al, *nx;
X
X for (al = head.next; al; al = nx)
X { nx = al->next;
X XtFree(al->alarm);
X XtFree(al->what);
X XtFree(al);
X }
X head.next = NULL;
X if (appResources.interval_id)
X { XtRemoveTimeOut(appResources.interval_id);
X appResources.interval_id = 0;
X }
X}
X
Xtypedef struct
X{ Widget sa_top;
X XtIntervalId sa_id;
X} AlarmStatus;
X
Xstatic void
XDisplayAlarmWindow(tleft, str1, str2)
X int tleft;
X String str1, str2;
X{
X Widget shell, form, title, aq, ah;
X Arg args[10];
X Cardinal nargs;
X char *fmt;
X char buf[255];
X AlarmStatus *als;
X
X /*
X * making the top level shell the override widget class causes it to
X * popup without window manager interaction or window manager
X * handles. this also means that it pops on the foreground of an
X * xlocked terminal and is not resizable by the window manager. If
X * any one finds that to be desirable behavior, then change the
X * transient class below to override.
X *
X * For now transient class is much better behaved
X */
X nargs = 0;
X XtSetArg(args[nargs], XtNallowShellResize, True); nargs++;
X XtSetArg(args[nargs], XtNinput, True); nargs++;
X XtSetArg(args[nargs], XtNsaveUnder, TRUE); nargs++;
X shell = XtCreatePopupShell("alarm", transientShellWidgetClass,
X toplevel, args, nargs);
X
X form = XtCreateManagedWidget("alarmPanel", panedWidgetClass,
X shell, NULL, 0);
X /*
X * create alarm status save area
X */
X als = (AlarmStatus *)XtMalloc(sizeof (AlarmStatus));
X if (als == NULL)
X Fatal("Out of memory\n");
X
X als->sa_top = shell;
X als->sa_id = NULL;
X if (appResources.autoquit)
X { als->sa_id = XtAddTimeOut(appResources.autoquit*1000,
X AutoDestroy, (caddr_t) als);
X }
X
X nargs = 0;
X XtSetArg(args[nargs], XtNshowGrip, False); nargs++;
X XtSetArg(args[nargs], XtNdefaultDistance, 2); nargs++;
X title = XtCreateManagedWidget("alarmForm", formWidgetClass,
X form, args, nargs);
X /*
X * Exit button Take "Quit" from resources
X */
X callbacks[0].callback = DestroyAlarm;
X callbacks[0].closure = (caddr_t) als;
X nargs = 0;
X XtSetArg(args[nargs], XtNcallback, callbacks); nargs++;
X XtSetArg(args[nargs], XtNfromHoriz, NULL); nargs++;
X XtSetArg(args[nargs], XtNleft, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNright, XtChainLeft); nargs++;
X aq = XtCreateManagedWidget("alarmQuit", commandWidgetClass,
X title, args, nargs);
X
X /*
X * Hold button Take "Hold" from resources
X */
X callbacks[0].callback = HoldAlarm;
X callbacks[0].closure = (caddr_t) als;
X nargs = 0;
X XtSetArg(args[nargs], XtNcallback, callbacks); nargs++;
X XtSetArg(args[nargs], XtNfromHoriz, aq); nargs++;
X if (!appResources.autoquit) {
X XtSetArg(args[nargs], XtNsensitive, False); nargs++;
X }
X XtSetArg(args[nargs], XtNleft, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNright, XtChainLeft); nargs++;
X ah = XtCreateManagedWidget("alarmHold", commandWidgetClass,
X title, args, nargs);
X
X if (tleft == 0)
X fmt = appResources.alarmnow;
X else
X fmt = appResources.alarmleft;
X
X if (fmt && *fmt)
X { nargs = 0;
X XtSetArg(args[nargs], XtNfromHoriz, ah); nargs++;
X XtSetArg(args[nargs], XtNleft, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNright, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
X XtSetArg(args[nargs], XtNfromVert, NULL); nargs++;
X XtSetArg(args[nargs], XtNvertDistance, 3); nargs++;
X (void) sprintf(buf, fmt, tleft);
X XtSetArg(args[nargs], XtNlabel, buf); nargs++;
X (void) XtCreateManagedWidget("alarmTitle", labelWidgetClass, title, args, nargs);
X }
X
X /*
X * Now the text which is the remainder of the panel
X */
X (void) sprintf(buf, "%s\n%s\n", str1, str2);
X nargs = 0;
X XtSetArg(args[nargs], XtNshowGrip, False); nargs++;
X XtSetArg(args[nargs], XtNstring, buf); nargs++;
X XtSetArg(args[nargs], XtNdisplayCaret, False); nargs++;
X (void) XtCreateManagedWidget("alarmText", asciiTextWidgetClass,
X form, args, nargs);
X
X XtPopup(shell, XtGrabNone);
X}
X
X/* ARGSUSED */
Xstatic void
XDestroyAlarm(w, als, call_data)
X Widget w;
X AlarmStatus *als;
X caddr_t call_data;
X{
X if (als->sa_id)
X XtRemoveTimeOut(als->sa_id);
X AutoDestroy(als, NULL);
X}
X
X/* ARGSUSED */
Xstatic void
XHoldAlarm(w, als, call_data)
X Widget w;
X AlarmStatus *als;
X caddr_t call_data;
X{
X if (als->sa_id)
X XtRemoveTimeOut(als->sa_id);
X XtSetSensitive(w, FALSE);
X}
X
X/* ARGSUSED */
Xstatic void
XAutoDestroy(als, id)
X AlarmStatus *als;
X XtIntervalId *id;
X{
X
X XtDestroyWidget(als->sa_top);
X XtFree(als);
X}
SHAR_EOF
if test 16260 -ne "`wc -c < 'xcal_alarm.c'`"
then
echo shar: error transmitting "'xcal_alarm.c'" '(should have been 16260 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcal_cal.man'" '(1102 characters)'
if test -f 'xcal_cal.man'
then
echo shar: will not over-write existing file "'xcal_cal.man'"
else
sed 's/^ X//' << \SHAR_EOF > 'xcal_cal.man'
X.TH XCAL_CAL (1)
X.SH NAME
Xxcal_cal \- interface to calendar(1) for xcal
X.SH SYNOPSIS
X.B xcal_cal
X[
X.B \-d
Xdirectory
X] [
X.B \-f
Xfile
X] [
X.B \-m
X]
X.SH DESCRIPTION
X.I Xcal_cal
Xreads through the files created by
X.IR xcal (1)
Xand creates a file suitable for use by
X.IR calendar (1).
XBy default, the files are found in a directory named
X``Calendar'' in the user's home directory;
Xan alternate directory may be specified with the
X.B \-d
Xflag.
XOutput goes by default into a file named ``.xcal''
Xin the user's home directory;
Xit may be overridden with the
X.B \-f
Xflag.
XIn both cases, if the argument given begins with a slash (`/'),
Xthen it will be taken as a full path name, not as a path relative to the
Xuser's home directory.
XIf the argument begins with the two character sequence `./' then
Xit will be taken relative to the current directory.
XThis last form is primarily intended for use while debugging.
XThe
X.B \-m
Xflag directs that multi-line entries in
X.I xcal
Xfiles be collected in their
Xentirety.
XBy default, only the first line is copied.
X.SH "SEE ALSO
Xxcal(1)
X.SH AUTHOR
XEd Gould, Mt.Xinu. Thanks Ed.
SHAR_EOF
if test 1102 -ne "`wc -c < 'xcal_cal.man'`"
then
echo shar: error transmitting "'xcal_cal.man'" '(should have been 1102 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcal_edit.c'" '(24926 characters)'
if test -f 'xcal_edit.c'
then
echo shar: will not over-write existing file "'xcal_edit.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'xcal_edit.c'
X#ifndef lint
Xstatic char *sccsid = "@(#)xcal_edit.c 3.15 (Hillside Systems) 1/16/91";
Xstatic char *copyright = "@(#)Copyright 1989,1990 Peter Collinson, Hillside Systems";
X#endif /* lint */
X/***
X
X* module name:
X xcal_edit.c
X* function:
X Deal with editable days
X This is derived from xcalendar's view of how to store things
X* history:
X Written November 1989
X Peter Collinson
X Hillside Systems
X* (C) Copyright: 1989 Hillside Systems/Peter Collinson
X
X For full permissions and copyright notice - see xcal.c
X***/
X#include <stdio.h>
X#include <ctype.h>
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/Shell.h>
X#include <X11/Xaw/AsciiText.h>
X#include <X11/Xaw/Text.h>
X#include <X11/Xaw/Command.h>
X#include <X11/Xaw/Label.h>
X#include <X11/Xaw/Paned.h>
X#include <X11/Xaw/Form.h>
X#include <X11/Xaw/Dialog.h>
X#include "xcal.h"
X#include <sys/stat.h>
X#ifdef SYSV
X# include <dirent.h>
X#else
X# include <sys/dir.h>
X#endif
X
Xtypedef struct editline
X{ struct editline *ed_next; /* Pointer to next */
X struct meWrap *ed_meWrap; /* Pointer to head of the chain */
X Cardinal ed_day; /* What day we are */
X Widget ed_popup; /* widget of editor popup */
X Widget ed_quit; /* widget of quit button */
X Widget ed_save; /* widget of save button */
X Widget ed_text; /* the text area */
X Cardinal ed_size; /* size of the buffer */
X char *ed_data; /* pointer to malloc'ed data buffer */
X} EditLine;
X
Xtypedef struct meWrap
X{ struct meWrap *mw_next;
X String mw_dir; /* name of the directory */
X Boolean mw_useTopDir; /* have found some data in the top dir */
X MonthEntry mw_me; /* what the external world sees */
X Instance *mw_list; /* list of toplevel widget for the */
X /* current set of displayed strips */
X EditLine *mw_ed; /* data being edited */
X} MeWrap;
X
X#define mw_year mw_me.me_year
X#define mw_month mw_me.me_month
X#define mw_have mw_me.me_have
X
X#define StripType(mw) (mw->mw_me.me_type)
X
Xstatic MeWrap *WrapBase; /* base of the list */
Xstatic MeWrap *WrapEnd; /* the last one in the list */
X
Xchar *MapStem; /* pointer to the string which is */
X /* where the map data is stored */
X
XBoolean FoundCalendarDir; /* whether the Calendar directory exists */
X
Xstatic XtCallbackRec callbacks[] = {
X {NULL,NULL},
X {NULL,NULL}
X};
X#define ClearCallbacks() bzero((caddr_t)callbacks, sizeof (callbacks))
X
X/*
X * Routine specs
X */
Xstatic MeWrap *NewMeWrap();
Xstatic MeWrap *MeWrapSearch();
Xstatic void DeRegisterMonth();
Xstatic Boolean WriteCalendarFile();
Xstatic Boolean WriteWeeklyFile();
Xstatic void DeleteCalendarFile();
Xstatic void SetAllButtons();
Xstatic void TextChanged();
Xstatic void FinishEditing();
Xstatic void CleanEditPanel();
Xstatic void CheckExit();
Xstatic void CheckDia();
Xstatic void YesCheck();
Xstatic void NoCheck();
Xstatic int DayMatch();
Xvoid StartDayEditor();
Xvoid Fatal();
X
X
X
X/*
X * Fire up the month entry environment
X * called once
X */
Xvoid
XInitMonthEntries()
X{ char buf[BUFSIZ];
X char *home;
X char *getenv();
X
X if (MapStem == NULL)
X { home = getenv("HOME");
X if (home == NULL)
X { /* should do things with password files */
X /* but for now we will simply die */
X Fatal("Xcal needs HOME defined in the environment");
X }
X (void) sprintf(buf, "%s/%s", home, appResources.directory);
X MapStem = XtNewString(buf);
X }
X if (access(MapStem, F_OK) < 0)
X FoundCalendarDir = False;
X else
X { FoundCalendarDir = True;
X /*
X * If we can see the directory, then lurch into it
X */
X if (chdir(MapStem) < 0)
X Fatal("Cannot change into %s", MapStem);
X }
X}
X
X/*
X * Get the entry for a specific month
X *
X * xcalendar files are all
X * xc<d><Mon><Year>
X * or
X * xc<dd><Mon><Year>
X *
X * where d or dd is the day (%02d would have been better)
X * <Mon> is a capitalised first three letters of the
X * English month name. If you need compatibility
X * don't redefine the short names in the resources
X * for this program.
X * <Year> is the full numeric year.
X *
X * We will follow this BUT we will also make this program
X * create subdirectories for new years
X * xy<Year>
X * to speed up file access
X */
XMonthEntry *
XGetMonthEntry(yr, mo)
X Cardinal yr;
X Cardinal mo;
X{
X MeWrap *mw;
X char *dir;
X DIR *dirp;
X#ifdef SYSV
X struct dirent *dp;
X#else
X struct direct *dp;
X#endif
X int da;
X Boolean inSubDir;
X char yearbuf[5];
X char monthbuf[4];
X
X if ((mw = MeWrapSearch(yr, mo)) == NULL)
X mw = NewMeWrap(yr, mo);
X
X if (!FoundCalendarDir)
X return(&mw->mw_me);
X
X /*
X * need this for string match
X */
X (void) sprintf(yearbuf, "%d", yr);
X (void) sprintf(monthbuf, "%s", appResources.smon[mo]);
X
X /* we are in the directory */
X /* so let's lookee here for the any files of interest */
X
X dir = ".";
X inSubDir = False;
X if (mw->mw_dir)
X { dir = mw->mw_dir;
X inSubDir = True;
X }
X
X if ((dirp = opendir(dir)) == NULL)
X Fatal("Cannot open directory: %s", MapStem);
X
X for (da = 1; da < 32; da++)
X if (mw->mw_have[da])
X { XtFree(mw->mw_have[da]);
X mw->mw_have[da] = NULL;
X }
X
X while ((dp = readdir(dirp)) != NULL)
X {
X#ifdef SYSV
X switch(strlen(dp->d_name))
X#else
X switch(dp->d_namlen)
X#endif
X {
X case 6: /* xy<Year> ?? */
X if (dp->d_name[0] == 'x' &&
X dp->d_name[1] == 'y' &&
X dp->d_name[2] == yearbuf[0] &&
X dp->d_name[3] == yearbuf[1] &&
X dp->d_name[4] == yearbuf[2] &&
X dp->d_name[5] == yearbuf[3] &&
X appResources.calCompat == False)
X { /*
X * well - we're wasting our time at the
X * top level - rejig things to work in the
X * subdirectory
X */
X inSubDir = True;
X mw->mw_useTopDir = False;
X mw->mw_dir = XtNewString(dp->d_name);
X closedir(dirp);
X if ((dirp = opendir(mw->mw_dir)) == NULL)
X Fatal("Cannot open directory %s/%s", MapStem, mw->mw_dir);
X
X }
X break;
X case 10: /* xc<d><Mon><Year> ?? */
X if (dp->d_name[0] == 'x' &&
X dp->d_name[1] == 'c' &&
X isdigit(dp->d_name[2]) &&
X dp->d_name[3] == monthbuf[0] &&
X dp->d_name[4] == monthbuf[1] &&
X dp->d_name[5] == monthbuf[2] &&
X dp->d_name[6] == yearbuf[0] &&
X dp->d_name[7] == yearbuf[1] &&
X dp->d_name[8] == yearbuf[2] &&
X dp->d_name[9] == yearbuf[3])
X { da = dp->d_name[2] - '0';
X mw->mw_have[da] = ReadCalendarFile(mw->mw_dir, dp->d_name);
X if (inSubDir == False)
X mw->mw_useTopDir = True;
X }
X break;
X case 11: /* xc<dd><Mon><Year> ?? */
X if (dp->d_name[0] == 'x' &&
X dp->d_name[1] == 'c' &&
X isdigit(dp->d_name[2]) &&
X isdigit(dp->d_name[3]) &&
X dp->d_name[4] == monthbuf[0] &&
X dp->d_name[5] == monthbuf[1] &&
X dp->d_name[6] == monthbuf[2] &&
X dp->d_name[7] == yearbuf[0] &&
X dp->d_name[8] == yearbuf[1] &&
X dp->d_name[9] == yearbuf[2] &&
X dp->d_name[10] == yearbuf[3])
X { da = (dp->d_name[2]-'0')*10 + (dp->d_name[3]-'0');
X mw->mw_have[da] = ReadCalendarFile(mw->mw_dir, dp->d_name);
X if (inSubDir == False)
X mw->mw_useTopDir = True;
X }
X break;
X }
X }
X closedir(dirp);
X return(&mw->mw_me);
X}
X
X/*
X * Get the entry for the weekly strip
X * Files are xw<Day> in the Calendar directory
X */
XMonthEntry *
XGetWeeklyEntry(yr, mo)
X Cardinal yr;
X Cardinal mo;
X{
X MeWrap *mw;
X int da;
X DIR *dirp;
X#ifdef SYSV
X struct dirent *dp;
X#else
X struct direct *dp;
X#endif
X
X if ((mw = MeWrapSearch(0, 0)) == NULL)
X mw = NewMeWrap(0, 0);
X
X if (!FoundCalendarDir)
X return(&mw->mw_me);
X
X if ((dirp = opendir(".")) == NULL)
X Fatal("Cannot open directory: %s", MapStem);
X
X for (da = 0; da < 7; da++)
X if (mw->mw_have[da])
X { XtFree(mw->mw_have[da]);
X mw->mw_have[da] = NULL;
X }
X
X while ((dp = readdir(dirp)) != NULL)
X {
X if (dp->d_name[0] == 'x' &&
X dp->d_name[1] == 'w' &&
X ((da = DayMatch(&dp->d_name[2])) != -1))
X {
X mw->mw_have[da] = ReadCalendarFile(NULL, dp->d_name);
X }
X }
X closedir(dirp);
X return(&mw->mw_me);
X}
X
X/*
X * Look for a short name match with a day
X */
Xstatic int
XDayMatch(day)
X String day;
X{
X register i;
X
X for (i = 0; i < 7; i++)
X if (strcmp(day, appResources.sday[i]) == 0)
X return(i);
X return (-1);
X}
X
X/*
X * create a new MapWrap area
X */
Xstatic MeWrap *
XNewMeWrap(yr, mo)
X Cardinal yr;
X Cardinal mo;
X{
X register MeWrap *mw;
X
X mw = (MeWrap *)XtMalloc(sizeof (MeWrap));
X bzero(mw, sizeof (MeWrap));
X if (WrapEnd)
X WrapEnd->mw_next = mw;
X WrapEnd = mw;
X if (WrapBase == NULL)
X WrapBase = mw;
X mw->mw_year = yr;
X mw->mw_month = mo;
X mw->mw_useTopDir = False;
X return(mw);
X}
X
X/*
X * Search the MapWrap list for a year
X */
Xstatic MeWrap *
XMeWrapSearch(yr, mo)
X Cardinal yr;
X Cardinal mo;
X{
X register MeWrap *mw;
X
X if (WrapBase)
X for (mw = WrapBase; mw; mw = mw->mw_next)
X if (yr == mw->mw_year && mo == mw->mw_month)
X return(mw);
X return(NULL);
X}
X
X/*
X * Register an instance of a month
X * Return a pointer to an instance structure so it can be filled
X * in by the caller
X */
XInstance *
XRegisterMonth(yr, mo, w)
X Cardinal yr;
X Cardinal mo;
X Widget w;
X{
X register MeWrap *mw;
X register Instance *ins;
X
X if ((mw = MeWrapSearch(yr, mo)) == NULL)
X mw = NewMeWrap(yr, mo);
X
X ins = (Instance *)XtMalloc(sizeof(Instance));
X ins->i_next = mw->mw_list;
X mw->mw_list = ins;
X ins->i_w = w;
X
X callbacks[0].callback = DeRegisterMonth;
X#ifdef LONG_IS_32_BITS
X callbacks[0].closure = (caddr_t)DatePack(0, 0, mo, yr);
X#else
X callbacks[0].closure = (caddr_t)DatePack(mo, yr);
X#endif
X
X XtAddCallbacks(w, XtNdestroyCallback, callbacks);
X return(ins);
X}
X
X/*
X * Return the head of an instance list - given a date
X */
XInstance *
XFindInstanceList(da)
X Date *da;
X{
X register MeWrap *mw;
X
X if ((mw = MeWrapSearch(da->year, da->month)) == NULL)
X return(NULL);
X return (mw->mw_list);
X}
X
X/*
X * Delete an instance
X */
X/* ARGSUSED */
Xstatic void
XDeRegisterMonth(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X Cardinal yr, mo;
X register Instance *ins, *inlast;
X register MeWrap *mw;
X
X yr = YrUnpack((Cardinal)closure);
X mo = MoUnpack((Cardinal)closure);
X
X if ((mw = MeWrapSearch(yr, mo)) == NULL)
X return;
X for (ins = mw->mw_list, inlast = NULL;
X ins;
X inlast = ins, ins = ins->i_next)
X { if (ins->i_w == w)
X { if (inlast)
X inlast->i_next = ins->i_next;
X else mw->mw_list = ins->i_next;
X XtFree(ins);
X return;
X }
X inlast = ins;
X }
X}
X
X
X/*
X * Read a calendar file into memory into a string
X * if the file is zero length then unlink and return NULL
X */
XString
XReadCalendarFile(dir, file)
X String dir;
X String file;
X{
X char fname[256];
X int fd;
X String destb;
X struct stat fsb;
X
X if (dir)
X { (void) sprintf(fname, "%s/%s", dir, file);
X file = fname;
X }
X if ((fd = open(file, 0)) < 0)
X Fatal("Cannot open: %s for reading", file);
X if (fstat(fd, &fsb) < 0)
X Fatal("Cannot fstat %s", file);
X
X if (fsb.st_size == 0)
X { (void) unlink(file);
X close(fd);
X return (NULL);
X }
X
X destb = (String) XtMalloc(fsb.st_size+1);
X
X if (read(fd, (String)destb, fsb.st_size) != fsb.st_size)
X Fatal("Read error on %s", file);
X
X close(fd);
X
X destb[fsb.st_size] = '\0';
X
X return(destb);
X}
X
X/*
X * Check to see if we should create the top directory
X */
XBoolean
XNeedTop()
X{
X if (!FoundCalendarDir)
X { if (mkdir(MapStem, 0700) == -1)
X { XBell(XtDisplay(toplevel), 0);
X fprintf(stderr, "xcal: Could not create: %s directory.\n", MapStem);
X perror("xcal: mkdir");
X fflush(stderr);
X return(False);
X }
X if (chdir(MapStem) < 0)
X { XBell(XtDisplay(toplevel), 0);
X fprintf(stderr, "xcal: Could not chdir into %s.\n", MapStem);
X perror("xcal: chdir");
X fflush(stderr);
X return(False);
X }
X FoundCalendarDir = True;
X }
X return(True);
X}
X
X/*
X * Write a calendar file creating any directories
X * which are needed
X * Return True is OK
X */
Xstatic Boolean
XWriteCalendarFile(mw, day, contents)
X register MeWrap *mw;
X Cardinal day;
X char *contents;
X{
X int fd;
X Cardinal len;
X char fname[256];
X char cname[16];
X
X len = strlen(contents);
X if (len == 0)
X { DeleteCalendarFile(mw, day);
X return(True);
X }
X if (!NeedTop())
X return(False);
X
X /*
X * So that looks OK
X * We can now create the output file.
X * However, we would like to put any new data into subdirectories
X * named for the year unless we are compatible with xcalendar
X */
X fname[0] = '\0';
X if (appResources.calCompat == False && mw->mw_useTopDir == False)
X { /* we have no data in the top directory */
X /* so let's create the directory name */
X (void) sprintf(fname, "xy%d", mw->mw_year);
X
X if (access(fname, F_OK) < 0)
X { if (mkdir(fname, 0700) < 0)
X { XBell(XtDisplay(toplevel), 0);
X fprintf(stderr, "xcal: Could not create: %s/%s directory.\n", MapStem, fname);
X perror("xcal: mkdir ");
X fflush(stderr);
X return(False);
X }
X }
X strcat(fname, "/");
X }
X /*
X * Whew - it looks as if we can now write the file
X */
X (void) sprintf(cname, "xc%d%s%d", day,
X appResources.smon[mw->mw_month],
X mw->mw_year);
X
X strcat(fname, cname);
X
X if ((fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0)
X { XBell(XtDisplay(toplevel), 0);
X fprintf(stderr, "xcal: Could not open %s/%s for writing.\n", MapStem, fname);
X perror("xcal: open");
X fflush(stderr);
X return(False);
X }
X
X if (write(fd, contents, len) != len)
X { XBell(XtDisplay(toplevel), 0);
X fprintf(stderr, "xcal: Write error %s/%s file.\n", MapStem, fname);
X perror("xcal: write");
X fflush(stderr);
X close(fd);
X return(False);
X }
X close(fd);
X /*
X * tickle the alarm system if we have altered `today'
X */
X if (today.day == day && today.month == mw->mw_month &&
X today.year == mw->mw_year)
X AlarmFilePoll(NULL);
X return(True);
X}
X
Xstatic void
XDeleteCalendarFile(mw, day)
X register MeWrap *mw;
X Cardinal day;
X{
X char fname[256];
X char cname[16];
X
X fname[0] = '\0';
X
X if (mw->mw_useTopDir == False)
X { /* we have no data in the top directory */
X /* so let's create the directory name */
X (void) sprintf(fname, "xy%d", mw->mw_year);
X
X if (access(fname, F_OK) < 0)
X return;
X strcat(fname, "/");
X }
X
X (void) sprintf(cname, "xc%d%s%d", day,
X appResources.smon[mw->mw_month],
X mw->mw_year);
X
X strcat(fname, cname);
X
X unlink(fname);
X
X /*
X * tickle the alarm system if we have altered `today'
X */
X if (today.day == day && today.month == mw->mw_month &&
X today.year == mw->mw_year)
X AlarmFilePoll(NULL);
X}
X
X/*
X * Write daily file out
X */
Xstatic Boolean
XWriteWeeklyFile(mw, day, contents)
X register MeWrap *mw;
X Cardinal day;
X char *contents;
X{
X int fd;
X Cardinal len;
X char *fname;
X
X fname = MakeWeeklyName(day);
X
X len = strlen(contents);
X if (len == 0)
X (void) unlink(fname);
X else
X { if ((fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0)
X { XBell(XtDisplay(toplevel), 0);
X fprintf(stderr, "xcal: Could not open %s/%s for writing.\n", MapStem, fname);
X perror("xcal: open");
X fflush(stderr);
X return(False);
X }
X
X if (write(fd, contents, len) != len)
X { XBell(XtDisplay(toplevel), 0);
X fprintf(stderr, "xcal: Write error %s/%s file.\n", MapStem, fname);
X perror("xcal: write");
X fflush(stderr);
X close(fd);
X return(False);
X }
X close(fd);
X }
X /*
X * tickle the alarm system if we have altered `today'
X */
X if (today.wday == day)
X AlarmFilePoll(NULL);
X
X return(True);
X}
X
X/*
X * Create a standard weekly file name
X */
XString
XMakeWeeklyName(day)
X Cardinal day;
X{
X static char fname[16];
X
X (void) sprintf(fname, "xw%s", appResources.sday[day]);
X return(fname);
X}
X
X/*
X * Get the contents of the current Weekly file if any
X */
XString
XGetWeeklyFile(day)
X Cardinal day;
X{
X char *fname;
X
X if (FoundCalendarDir == False)
X return (NULL);
X
X fname = MakeWeeklyName(day);
X
X if (access(fname, F_OK) < 0)
X return(NULL);
X
X return (ReadCalendarFile(NULL, fname));
X}
X
X/*
X * Start up an editor window from the callback
X * Pass the calling widget so we can change its contents
X * after the edit
X */
X/* ARGSUSED */
Xvoid
XStartEditing(w, da)
X Widget w;
X Date *da;
X{
X register MeWrap *mw;
X register EditLine *ed;
X
X if ((mw = MeWrapSearch(da->year, da->month)) == NULL)
X mw = NewMeWrap(da->year, da->month); /* shouldn`t happen */
X /*
X * see if we are already editing this day
X */
X for (ed = mw->mw_ed; ed; ed = ed->ed_next)
X { if (ed->ed_day == da->day)
X { /* we are! */
X /* Complain via a popup */
X switch (StripType(mw))
X {
X case ME_MONTHLY:
X NoEditIsPossible(w, da);
X break;
X case ME_WEEKLY:
X NoDayEditIsPossible(w, da->day);
X break;
X }
X return;
X }
X }
X /*
X * Things are looking OK
X * Create a new editing record
X */
X ed = (EditLine *)XtMalloc(sizeof(EditLine));
X bzero(ed, sizeof (EditLine));
X ed->ed_day = da->day;
X ed->ed_meWrap = mw; /* help for unlinking */
X /*
X * Do we have a string now
X */
X if (mw->mw_have[da->day])
X { ed->ed_size = appResources.textbufsz + strlen(mw->mw_have[da->day]) + 1;
X ed->ed_data = XtMalloc(ed->ed_size);
X strcpy(ed->ed_data, mw->mw_have[da->day]);
X }
X else
X { ed->ed_data = XtMalloc(ed->ed_size = appResources.textbufsz);
X *ed->ed_data = '\0';
X }
X /*
X * put the record into the list
X */
X ed->ed_next = mw->mw_ed;
X mw->mw_ed = ed;
X /*
X * We fiddle with the source widget too
X * Desensitise visible source widgets
X * If the user starts up another strip for this month
X * then the NoEditIsPossible() code above copes
X */
X SetAllButtons(mw->mw_list, da->day, False);
X /*
X * Now we should start up the edit window for this
X * month
X */
X StartDayEditor(mw, da);
X}
X
X
X/*
X * Set all the relevant buttons in a widget list to off or on
X */
Xstatic void
XSetAllButtons(ins, day, val)
X Instance *ins;
X Cardinal day;
X Boolean val;
X{
X for (;ins; ins = ins->i_next)
X XtSetSensitive(ins->i_day_info[day], val);
X}
X
X/*
X * Start up a day editor
X * Modelled on xcalendar.c
X */
Xvoid
XStartDayEditor(mw, da)
X register MeWrap *mw;
X register Date *da;
X{
X register EditLine *ed = mw->mw_ed; /* top of the list is ours */
X Widget lw, et;
X Widget frame;
X Arg args[10];
X Cardinal nargs;
X char buf[64];
X extern Widget toplevel;
X void FinishEditing();
X void SaveEdits();
X void ClearEntry();
X void TextChanged();
X void EditHelp();
X
X ed->ed_popup = XtCreatePopupShell("edit", topLevelShellWidgetClass, toplevel, NULL, 0);
X
X /*
X * Create the title line - which is a form containing
X * buttons and a date label
X */
X et = XtCreateManagedWidget("panel", panedWidgetClass, ed->ed_popup, NULL, 0);
X
X nargs = 0;
X XtSetArg(args[nargs], XtNshowGrip, False); nargs++;
X XtSetArg(args[nargs], XtNskipAdjust, True); nargs++;
X XtSetArg(args[nargs], XtNdefaultDistance, 1); nargs++;
X frame = XtCreateManagedWidget("title", formWidgetClass, et, args, nargs);
X /*
X * Take label "quit" from resources
X */
X callbacks[0].callback = FinishEditing;
X callbacks[0].closure = (caddr_t)ed;
X nargs = 0;
X XtSetArg(args[nargs], XtNcallback, callbacks); nargs++;
X XtSetArg(args[nargs], XtNfromHoriz, NULL); nargs++;
X XtSetArg(args[nargs], XtNleft, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNright, XtChainLeft); nargs++;
X ed->ed_quit = XtCreateManagedWidget("quit", commandWidgetClass, frame, args, nargs);
X
X /*
X * Take label "save" from resources
X */
X callbacks[0].callback = SaveEdits;
X callbacks[0].closure = (caddr_t)ed;
X nargs = 0;
X XtSetArg(args[nargs], XtNcallback, callbacks); nargs++;
X XtSetArg(args[nargs], XtNfromHoriz, ed->ed_quit); nargs++;
X XtSetArg(args[nargs], XtNleft, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNright, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNsensitive, False); nargs++;
X lw = ed->ed_save = XtCreateManagedWidget("save", commandWidgetClass, frame, args, nargs);
X
X if (appResources.giveHelp)
X {
X /*
X * Take label "help" from resources
X */
X callbacks[0].callback = EditHelp;
X callbacks[0].closure = (caddr_t)0;
X nargs = 0;
X XtSetArg(args[nargs], XtNcallback, callbacks); nargs++;
X XtSetArg(args[nargs], XtNfromHoriz, lw); nargs++;
X XtSetArg(args[nargs], XtNleft, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNright, XtChainLeft); nargs++;
X lw = XtCreateManagedWidget("help", commandWidgetClass, frame, args, nargs);
X }
X
X switch (StripType(mw))
X {
X case ME_MONTHLY:
X PlaceStr(buf, da, appResources.editYearIs2);
X break;
X case ME_WEEKLY:
X (void) strcpy(buf, appResources.day[da->day]);
X break;
X }
X nargs = 0;
X XtSetArg(args[nargs], XtNlabel, buf); nargs++;
X XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
X XtSetArg(args[nargs], XtNfromHoriz, lw); nargs++;
X XtSetArg(args[nargs], XtNfromVert, NULL); nargs++;
X XtSetArg(args[nargs], XtNvertDistance, 2); nargs++;
X XtSetArg(args[nargs], XtNleft, XtChainLeft); nargs++;
X XtSetArg(args[nargs], XtNright, XtChainRight); nargs++;
X lw = XtCreateManagedWidget("date", labelWidgetClass, frame, args, nargs);
X
X /*
X * The text widget is in the pane below
X * The Scroll Attributes are controlled from the application
X * defaults file
X */
X callbacks[0].callback = TextChanged;
X callbacks[0].closure = (caddr_t)ed;
X nargs = 0;
X XtSetArg(args[nargs], XtNshowGrip, False); nargs++;
X XtSetArg(args[nargs], XtNstring, ed->ed_data); nargs++;
X XtSetArg(args[nargs], XtNeditType, XawtextEdit); nargs++;
X XtSetArg(args[nargs], XtNlength, ed->ed_size); nargs++;
X XtSetArg(args[nargs], XtNuseStringInPlace, True); nargs++;
X XtSetArg(args[nargs], XtNcallback, callbacks); nargs++;
X ed->ed_text = XtCreateManagedWidget("text", asciiTextWidgetClass, et, args, nargs);
X
X XtPopup(ed->ed_popup, XtGrabNone);
X
X}
X
X/*
X * Callback for text widget
X * This gets called before the string is updated
X */
X/* ARGSUSED */
Xstatic void
XTextChanged(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X register EditLine *ed = (EditLine *)closure;
X
X XtSetSensitive(ed->ed_save, True);
X}
X
X
X/*
X * Callback routines
X */
X/* ARGSUSED */
Xvoid
XSaveEdits(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X register EditLine *ed = (EditLine *)closure;
X register Instance *ins;
X register MeWrap *mw;
X register Cardinal day;
X Arg args[3];
X
X mw = ed->ed_meWrap;
X day = ed->ed_day;
X
X switch (StripType(mw))
X {
X case ME_MONTHLY:
X if (WriteCalendarFile(mw, day, ed->ed_data) == False)
X return;
X break;
X case ME_WEEKLY:
X if (WriteWeeklyFile(mw, day, ed->ed_data) == False)
X return;
X break;
X }
X /*
X * Otherwise change the displayed string
X */
X if (mw->mw_have[day])
X XtFree(mw->mw_have[day]);
X mw->mw_have[day] = XtMalloc(strlen(ed->ed_data)+1);
X strcpy(mw->mw_have[day], ed->ed_data);
X
X XtSetArg(args[0], XtNlabel, mw->mw_have[day]);
X if (*mw->mw_have[day])
X { XtSetArg(args[1], XtNforeground, appResources.marked.fg);
X XtSetArg(args[2], XtNbackground, appResources.marked.bg);
X }
X for (ins = mw->mw_list; ins; ins = ins->i_next)
X { if (*mw->mw_have[day] == '\0')
X { XtSetArg(args[1], XtNforeground, ins->i_col.fg);
X XtSetArg(args[2], XtNbackground, ins->i_col.bg);
X }
X XtSetValues(ins->i_day_info[day], args, 3);
X }
X XtSetSensitive(ed->ed_save, False);
X
X /*
X * worry about updating the memo system
X */
X
X switch (StripType(mw))
X {
X case ME_MONTHLY:
X if (today.day == day && today.month == mw->mw_month &&
X today.year == mw->mw_year)
X UpdateMemo();
X break;
X case ME_WEEKLY:
X if (today.wday == day)
X UpdateMemo();
X break;
X }
X
X}
X
Xstatic void
XFinishEditing(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X register EditLine *ed = (EditLine *)closure;
X register MeWrap *mw;
X Cardinal day;
X
X mw = ed->ed_meWrap;
X day = ed->ed_day;
X
X if (mw->mw_have[day] == NULL)
X { if (*ed->ed_data)
X { CheckExit(ed);
X return;
X }
X }
X else
X if (strcmp(mw->mw_have[day], ed->ed_data))
X { CheckExit(ed);
X return;
X }
X CleanEditPanel(w, ed, call_data);
X}
X
Xstatic void
XCleanEditPanel(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X register EditLine *ed = (EditLine *)closure;
X register EditLine *edl, *eds;
X register MeWrap *mw;
X Cardinal day;
X Widget popup;
X
X mw = ed->ed_meWrap;
X day = ed->ed_day;
X popup = ed->ed_popup;
X
X XtFree(ed->ed_data);
X
X for (edl = NULL, eds = mw->mw_ed;
X eds;
X edl = eds, eds = eds->ed_next)
X { if (eds == ed)
X { if (edl)
X edl->ed_next = ed->ed_next;
X else mw->mw_ed = ed->ed_next;
X break;
X }
X }
X XtFree(ed);
X XtPopdown(popup);
X XtDestroyWidget(popup);
X
X SetAllButtons(mw->mw_list, day, True);
X}
X
X/*
X * We are trying to leave with saving the data
X * let us see if the user really wants to
X */
Xstatic void
XCheckExit(ed)
X register EditLine *ed;
X{
X
X DialogPopup(ed->ed_quit, CheckDia, ed);
X}
X
X/*
X * Here we do the work
X */
Xstatic void
XCheckDia(pop, ed)
X Widget pop;
X EditLine *ed;
X{
X Widget dia;
X
X /* Take "Save file?" from resources */
X dia = XtCreateManagedWidget("check", dialogWidgetClass, pop, NULL, 0);
X XawDialogAddButton(dia, "yes", YesCheck, ed);
X XawDialogAddButton(dia, "no", NoCheck, ed);
X}
X
X/* ARGSUSED */
Xstatic void
XYesCheck(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X SaveEdits(w, closure, call_data);
X CleanEditPanel(w, closure, call_data);
X XtDestroyWidget(XtParent(XtParent(w)));
X
X}
X
X/* ARGSUSED */
Xstatic void
XNoCheck(w, closure, call_data)
X Widget w;
X caddr_t closure;
X caddr_t call_data;
X{
X CleanEditPanel(w, closure, call_data);
X XtDestroyWidget(XtParent(XtParent(w)));
X}
X
X
X/*
X * Slighty formatted XtError
X */
X/* VARARGS1 */
Xvoid
XFatal(fmt, a, b)
X char *fmt;
X char *a;
X char *b;
X{
X char buf[BUFSIZ];
X
X (void) sprintf(buf, fmt, a, b);
X XtError(buf);
X /* NOTREACHED */
X}
SHAR_EOF
if test 24926 -ne "`wc -c < 'xcal_edit.c'`"
then
echo shar: error transmitting "'xcal_edit.c'" '(should have been 24926 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
--
Dan Heller
O'Reilly && Associates Z-Code Software Comp-sources-x:
Senior Writer President comp-sources.x at uunet.uu.net
argv at ora.com argv at zipcode.com
More information about the Comp.sources.x
mailing list