Xcal is a calendar program. For more details see Part 1 of this posting

Part 8 of 8
--shar starts here--
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 8 (of 8)."
# Contents:  xcal.man xcal_edit.c
# Wrapped by pc@hillside on Wed Nov 17 11:24:37 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xcal.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xcal.man'\"
else
echo shar: Extracting \"'xcal.man'\" \(25369 characters\)
sed "s/^X//" >'xcal.man' <<'END_OF_FILE'
X.TH xcal 1 "September 1990" "X Version 11 R5"
X.SH NAME
Xxcal \-  calendar with alarms and a notebook for X11
X.SH SYNTAX
X.B xcal
X[
X.B \-debug
X][
X.B \-alarmscan
X][
X.B \-format
X.I fmt
X][
X.B \-editformat
X.I fmt
X][
X.B \-stripformat
X.I fmt
X][
X.B \-clocktick
X.I tick
X][
X.B \-u
X.I username
X]
X.SH DESCRIPTION
X.de EX		\"Begin example
X.ne 5
X.if n .sp 1
X.if t .sp .5
X.nf
X.ta +8u*\w'\0'u +8u*\w'\0'u +8u*\w'\0'u +8u*\w'\0'u +8u*\w'\0'u +8u*\w'\0'u
X..
X.de EE
X.fi
X.if n .sp 1
X.if t .sp .5
X..
X.I Xcal
Xis an interactive calendar program.
XThe user interface has several levels.
XWhen started,
X.I xcal
Xdisplays today's date in a small command box
Xthat is intended to sit on the screen as a companion to the
X.I xclock
Xprogram.
XThe format of the command box may be altered using the resource manager, so you
Xare not stuck with my preferred layout.
XYou can set the time in the window too, if you wish (see the format resource).
XAccess to further levels in
X.I xcal
Xis made by clicking a mouse button in the command box.
XThe command box is split into several areas and clicking on one of these
Xwill popup a window supporting a new function.
X.PP
XClicking with mouse button one on the question mark
Xin the command box pops up a help window.
X.I Xcal
Xcomes with many help buttons.
XWhen you are convinced they are no longer
Xany use to you, they can all be turned off using an X resource.
X.LP
XA small button containing a `mouse' bitmap
Xcan be pressed with mouse button one to inspect appointments for today.
XThis generates a panel showing information from the calendar file for today and
Xinformation from a set of seven daily files holding regular commitments.
XThe panel also contains a text scratchpad, `the memo panel'.
XThis allows the editing of a memo file.
X.LP
XThe calendar functions are accessed by clicking a mouse
Xbuttons inside date portion of the command window.
X.IP 1)
XMouse button one pops up a calendar `strip' for the current month.
XThe strip has some header lines and then one line per day of the month.
XThe `line per day' display contains the day in the month and the
Xday of the week.
XToday may be highlighted specially \- the notion of Today alters at midnight.
XThe strip has a help button which displays a description of the panel.
XCommand buttons in the header line allows the user to bring up a strip
Xfor the previous or the next month.
X.IP 2)
XPressing mouse button two in the date area will bring up a dialogue box
Xwhich allows the user to select any month of any year (yes, September 1752
Xis supported).
XThe month may be input as month name or abbreviation, even though the
Xprompt indicates a more restrictive format.
X.IP 3)
XPressing mouse button 3 in the date label causes the whole program to
Xexit, a dialog box is used to ask the user for confirmation.
X.LP
XLike
X.IR xcalendar ,
Xdaily events are stored in set of files, one for each day.
XIf the file exists when the strip is started,
Xits data is displayed as the label in the command
Xbutton on the right-hand side of the month strip.
XThe file is created and edited by entering a simple text editor
X(the standard text widget) which is started
Xby pressing the right hand side of the appropriate day line in the strip.
XYou can also add data to the file by selecting a string on the
Xscreen and clicking with
Xthe middle button on the right-hand side of the month strip.
XThe string is appended to the file for the day.
XThis short-hand allows one entry to be loaded into several day files.
X.LP
XThe width of the
Xmonth strip is computed from the width of the header. 
XUsers who
Xwish to display a wider strip to show more of the stored information
Xshould widen the strip using the
X.I minStripWidth
Xresource (see below).
X.LP
XThe colours and fonts used in the strip is controllable by resources.
XThe widget that comprises each line in the strip is tagged with the short
Xform name of the day, so it's easy to vary the strip display showing weekends
Xdifferently from the weekdays.
X.LP
XData files are stored in a directory usually called
X.B Calendar
Xunder the user's home directory.
XEach file is stored in a subdirectory containing all the data
Xfor a particular year.
XThis is incompatible with 
X.IR xcalendar ,
Xthe user may specify that the compatibility should be maintained.
X.LP
XAlarms are supported by
X.IR xcal .
XWhen a line in the data file starts with a digit, it is
Xassumed to be a time specification and a candidate for an alarm.
XThe line contains a string giving the alarm time and a text string
Xdisplayed in a dialogue alarm box that pops up when the alarm fires.
XYou can also arrange for countdown alarms to fire, so that you can
Xbe told that something is about to happen.
XThese dialogue boxes will automatically go away after two minutes, unless the
X`Stick' button is pressed glueing the box onto the screen.
XThe box can be made to go away at any time by hitting the `Unpin' button.
X.LP
XWhen specifying alarms,
X.I Xcal
Xtries to be liberal about the times that it understands.
XTime specifications are: h, hh, hhmm, hmm, hh:mm, h:mm, hh.mm, h.mm;
Xall of these may be optionally followed by an am/pm indicator \- one
Xof: A, a, AM, am, Am, aM, P, p, PM, pm, Pm, pM.
XTimes must always be followed by at least one space or tab.
XSome legal examples are:
X.br
X.nf
X	12:00 Lunch - Meet Joe at Burger King
X	14.30 Meeting in the cafeteria
X	2:30p Ring Mark
X	7pm Pizza
X.fi
X.LP
XYou can make a time like 2:30 mean 14:30 by setting the resource
X.I AlarmWarp
Xto be true.
XIf this is the case, an alarm hour will be promoted to a PM time if it is found
Xto be between the range of
Xzero and the value of the resource
X.IR minAlarmWarp .
X.LP
X.I Xcal
Xalso supports timed command execution from the data file.
XTo trigger a command, the data part of the line starts
Xwith an exclamation mark, eg:
X.br
X	4.30pm !xmessage -message 'ring home'
X.LP
XThe exclamation mark can also be replaced by the string `%cron'.
XIt is also possible to make 
X.I xcal
Xexecute a command whenever an alarm is triggered, see the
X.I Cmd
Xresource below.
X.LP
XThe memo function of
X.I Xcal
Xis accessed by pressing the non-date portion of the command window.
XThis shows a bitmap diagram of three mouse buttons.
XClicking the left mouse button in this area brings up a complex panel,
Xclicking on the button again will pop it back down again.
XThe top half of the panel displays the information held in the diary
Xfor today; pressing the Edit button here will start an edit box for today.
XThe next section of the panel displays the information held in the
Xweekly files.
XAgain you cannot directly change the text in this area, you must
Xpress on the Edit button to bring up a strip enabling you to
Xchange things.
XThe bottom portion of the panel is an edit window displaying the contents
Xof a file usually called `memo' in the Calendar directory.
XThe idea of this panel is to allow you to access your current information
Xin one button click.
X.LP
XIt is obviously possible to change
X.IR Xcal 's
Xdata files without using the inbuilt text widget editor.
XIn general,
X.I Xcal
Xwill not notice this.
XEditing random day files with a standard text editor will not
Xchange the contents of any displayed strips until the strips are
Xpopped down and up again.
X.I Xcal
Xknows what days have been altered when the text widget is used to
Xedit the day files, and will reflect any change immediately into
Xthe displayed strips.
X.LP
XYou can make 
X.I Xcal
Xtake notice of today's date file and the current memo file.
XThe `Update' resource sets a polling time in seconds.
XWhen the clock fires and today's file has been altered,
Xthe alarm list is rebuilt from the current date file
Xand the memo panel is updated.
XThe bottom part of the memo panel is also updated if the `memo'
Xfile has been altered on the clock tick.
X.SH OPTIONS
X.LP
XVersion 4 of
X.I Xcal
Xpermits one user to view another's calendar by giving the
X.I \-u
Xoption followed by the user's login name.
XThe user's calendar storage area
Xis assumed to be called `Calendar' in their home directory.
XThe facilities are somewhat rudimentary.
XFirst, the main date box will have the user's login name appended to the
Xdate format string.
XWhen a month strip is generated, you will be given read-only access to their
Xcalendar files, assuming that the file permissions allow you to read them.
XThis is intended to be one step better than using
X.I cat
Xon their calendar files.
X.LP
XThe
X.I \-debug
Xswitch causes contents of the initial date window to be incremented very
Xfrequently, this allows some testing of the program.
X.LP
XThe
X.I \-alarmscan
Xswitch prints debugging information about the alarm system on standard output.
X.LP
XThe argument following the
X.I \-format
Xis a date format
Xused to display dates in the top level window
X(see below, the
X.I Format
Xresource).
XChanging this to include a time format will make
X.I xcal
Xdisplay a clock in your top level window.
X.LP
XThe argument following the
X.I \-stripfmt
Xargument is a date format used to display month names and years in the monthly
Xcalendar strip.
X(see the resource
X.IR StripFmt ).
X.LP
XSimilarly, the
X.I \-editfmt
Xargument is the format for dates used in an edit window
X(see the
X.I Editfmt
Xresource).
X.LP
XThe
X.I \-clocktick
Xargument is used to set the clock update time of the main date window,
Xshould a time be displayed as well as the date.
XSee the
X.I Clocktick
Xresource.
X.SH RESOURCES
XAs with all standard X applications,
X.I xcal
Xmay be customised through 
Xentries in the resource manager.
XIt is a serious mistake to install
X.I Xcal
Xwithout putting the resource initialisation file 
X.I Xcal
Xin 
X.IR /usr/lib/X11/app-defaults .
XResource class names are listed below;
Xresource instance names are identical, except the first letter is in
Xlower case.
XThe following resource manager entries are defined:
X.LP
X.TP "\w'ReverseVideoMarkNNN'u"
X.B Debug
XIf True enables accelerated time.
XAlarms will not function correctly.
XDefault: False.
X.TP
X.B OtherUser
Xthe name of the user whose calendar files will be inspected.
XThis is usually set by the
X.B \-u
Xoption.
X.TP
X.B AlarmScan
XIf True enables printing of alarm related debugging information
Xto the standard output.
XDefault: False.
X.TP
X.B ReverseVideo
XIf true display the output in reverse video.
XDefault: False.
X.TP
X.B Format
XThis is a format string used to create the contents of the top command
Xbutton and the memo box.
XThe format is aimed at the system routine:
X.IR strftime .
XI have chosen to use the system routine because it makes it easier for
Xnon-english language sites to generate their own formats.
XHowever, this means that the names used for months and days may not be compatible
Xwith the ones set in the resources below.
XAny characters in the format string are passed to the output unchanged
Xunless they specify a format.
XFormat letters are preceded by a `%' character and can be found in the
Xdocumentation for
X.I strftime
Xon your system.
XThe SunOS 4.1.3 routine supports:
X.EX
X%%	same as %
X%a	day of week using abbreviated name
X%A	day of week using full weekday names
X%b	(%h) month, using locale's abbreviated names
X%B	month, using locale's full names
X%c	date and time as %x %X
X%C	date and time, in local long-format date and
X	time representation
X%d	day of month (01-31)
X%D	date as %m/%d/%y
X%e	day of month (1-31; single digits are preceded  by a blank)
X%H	hour (00-23)
X%I	hour (00-12)
X%j	day number of year (001-366)
X%k	hour (0-23; single digits are preceded by a blank)
X%l	hour (1-12; single digits are preceded by a blank)
X%m	month number (01-12)
X%M	minute (00-59)
X%n	same as \en
X%p	local equivalent of AM or PM
X%r	time as %I:%M:%S %p
X%R	time as %H:%M
X%S	seconds (00-59)
X%t	same as \et
X%U	week number of year (01-52), Sunday is the first day of the week
X%W	week number of year (01-52), Monday is the first day of the week
X%x	date, using locale's date format
X%X	time, using locale's time format
X%y	year within century (00-99)
X%Y	year, including century (fore example, 1988)
X%Z	time zone abbreviation
X.EE
XThe default is "%A %d %B %Y", printing the day, the date, the month and the
Xfull year.
XI prefer to use "%A %e %B %Y", but this does not seem to be portable to
Xdifferent systems.
XThe format string is scanned to determine the update frequency that
Xis needed to maintain a correct date image.
XThe default needs updating every 24 hours, if you insert an AM/PM format
Xthen the strip will be updated every 12 hours.
XAdding an hour specification will cause an update every hour and specifying
Xminutes or seconds will cause appropriate behaviour.
X.TP
X.B ClockTick
XIf you specify a second hand in the main
Xdate string and only want it updated every 30 seconds (say)
Xthen setting the ClockTick resource to 30 will force an update for that period.
XDefault: 0 (derived from the
X.I Format
Xstring).
X.TP
X.B StripFmt
Xis used to format the date line at the top of each strip.
XThis uses an internal version of the
X.I strftime
Xroutine that only
Xsupports format characters relating to months, years and days.
XThe supported format characters are: %A, %a, %B, %b, %h, %D, %d, %e, %m, %n,
X%t, %x, %y and %%.
XLong/short day and month names are taken from the resources.
XDefault: "%B %y".
X.TP
X.B EditFmt
Xprovides the format string for any edit window.
XThis uses the same code as
X.BR StripFmt .
XDefault: "%A %d %B %Y".
XAgain, I prefer to use "%A %e %B %Y".
X.TP
X.B MarkToday
XIf True then highlight today.
XDefault True.
X.TP
X.B TodayBackground
Xthe background colour when marking, default Black.
X.TP
X.B TodayForeground
Xthe foreground colour when marking today, default White.
X.TP
X.B FontToday
XToday may be marked by using a special font, if this is desired the
Xfont is given by this resource.
XDefault is to use the default font.
X.TP
X.B Directory
XThe name of the directory under the home directory
Xwhere the day files are stored.
XDefault: Calendar.
X.TP
X.B XcalendarCompat
XIf true then subdirectories are not created in the Calendar directory.
XThis flag is not relevant when files are being read, so users
Xcan use both programs with existing data files.
XDefault: False.
X.TP
X.B GiveHelp
XIf True than access to the help information is given.
XIf False, help buttons disappear returning screen real-estate to the user.
XYou should resist setting this to False in the default resources file.
XDefault: True.
X.TP
X.B HelpFromFile
XThe
X.I Xcal
Xprogram will usually have help strings compiled into it.
XThese are in English and it may be desirable to use help data in other languages.
XIf this resource is true, it forces
X.I Xcal
Xto look in a data file for the help strings.
XDefault: False.
X.TP
X.B HelpFile
Xgives the name of the file used as a database for the help system,
Xaccessed when
X.B HelpFromFile
Xis True.
XDefault: /usr/lib/X11/XCal.help.
X.TP
X.B InitialCalendar
XIf True then the calendar for this month is automatically displayed on
Xstartup.
XIf False, the calendar is not automatically displayed.
XDefault: False.
X.TP
X.B InitialEdit
XIf True then an edit window for today is automatically displayed on
Xstartup if a file exists for today's date.
XIf False, the edit window is not automatically displayed.
XDefault: False.
X.TP
X.B InitialMemo
XIf True then the memo window is automatically displayed on startup.
XDefault: False.
X.TP
X.B UseWmTitle
XIf True display the month and the year at the head of each strip.
XThis information is duplicated if your window manager uses titles
Xso it is nice to be able to turn it off.
XDefault: True.
X.TP
X.B TextBufferSize
Xthe maximum number of bytes which we are prepared to deal with in an
Xedit window.
XDefault: 2048 bytes.
X.TP
X.B Alarms
Xwhether or not to enable the alarm system.
XDefault: True.
X.TP
X.B ExecAlarms
Xif the alarm system is active,
Xwhether or not to invoke timed-execution commands.
XDefault: True.
X.TP
X.B Update
XWhen scanning for alarms in the current day file
X.I Xcal
Xinspects it at program startup time and also when it is edited using the
Xnormal built-in editing mechanism.
XHowever, if some external program changes t file
X.I xcal
Xwill not see the new contents and new alarms will not be set.
XSetting this resource to non-zero will force 
X.I xcal
Xto scan the file every `update' seconds
Xlooking for alterations in size and modification date.
XWhen it detects that the file is altered, then
Xit will rebuild the internal alarm list.
XDefault: zero.
X.TP
X.B Nbeeps
XWhen an alarm window is popped up, it is accompanied by `Nbeeps' beeps.
XDefault: 3.
X.TP
X.B Volume
XControl the loudness of the beep. Default: 50.
X.TP
X.B Cmd
XThis resource contains a command that is executed by calling the shell
Xwhen every alarm is triggered.
XThe command is passed the contents of the data line as one argument.
X.TP
X.B Countdown
Xcontains a comma separated string of numbers; for example: 10,5,0.
XThe string allows the user to customise warning alarms: so in the
Xexample, alarm boxes will be displayed 10 minutes before the stated time,
X5 minutes before the stated time and exactly on the stated time.
XCommands lines in the data prefaced by a `!' will always be triggered
Xexactly at the stated time.
XDefault: 10,0.
X.TP
X.B Autoquit
XEach dialogue box containing an alarm message contains an `Unpin' button
Xallowing the user to remove the message from the screen by using mouse button one.
XAdditionally, the message box can remove itself from the screen after
Xa specified period, this resource gives that timeout in seconds.
XIf the resource is set to zero, then the user is always forced to take
Xexplicit action to remove the box.
XDefault: 120, alarm boxes disappear after 2 mins.
X.TP
X.B Alarmleft
Xcontains a
X.I printf
Xstring that is displayed in the label at the top
Xof an alarm box when countdown is in operation and
Xthere is some time before the stated time.
XThe time before the stated time is supplied as the second argument to printf.
XDefault: ``%d minutes before...''
X.TP
X.B Alarmnow
Xcontains the 
X.I printf
Xstring that is displayed in the label at the top
Xof an alarm box when the stated time is reached.
XDefault: ``Time is now...''.
X.TP
X.B UseMemo
Xenables the use of the memo feature.
XThis defaults to ``True'', but is present to allow users to make 
X.I XCal
Xhave as it used to.
X.TP
X.B MemoLeft
Xaffects the placing of the memo button in the top level date window.
XThe default is `True' meaning that the button box is placed on the left
Xof the date portion.
XSetting this to `False' will place the button box to the right of the
Xdate portions.
X.TP
X.B MemoFile
Xgives the name of the memo file within the Calendar directory.
XThe default is `memo'.
X.TP
X.B MaxDisplayLines
Xcontrols the maximum number of text lines that can placed in the
Xtop half of the memo panel.
XThe top hald will normally size to the number of lines in the diary
Xfile for the day, unless the number of lines exceed the value in
Xthis resource.
XThis ensures that today's events do not dominate the memo panel.
XDefault: 5 lines.
X.TP
X.B MaxStripHeight
Xcontrols the maximum height of a strip.
XA scroll bar will be added into the date part of the scrip of the contents
Xare larger than this number.
XIf unset, this defaults to the height of the screen.
XDefault: unset.
X.TP
X.B MinStripWidth
XThe width of month strips are set by the top line, which usually
Xdisplays the month and year.
XThe whole strip can be widened from this default value by setting this
Xresource to be non-zero.
XDefault: zero (i.e. off).
X.TP
X.B January
X.B February
Xand so on.
XThe names of the long form of the month name.
X.TP
X.B Jan
X.B Feb
Xand so on.
XA short form of the month name - done this way because I doubt that
Xwriting with %3s works in all languages.
XChanging this resource means that the data file will no longer be
Xcompatible with
X.I xcalendar .
X.TP
X.B Sunday
X.B Monday
Xand so on.
XThe
X.I long
Xnames of the days: Sunday, Monday etc.
XThese are used in titles: the top level widget, the title of an edit window
Xand the memo frame.
X.TP
X.B Sun
X.B Mon
Xand so on.
XThe short names of the days \- used in date strips.
X.TP
X.B Private
XContains the string `Private calendar entry' and is used when the \-u option
Xis in force. It is displayed when a calendar file entry is unreadable
Xby the caller.
X.TP
X.B Alarmleft
XContains the string `%d minutes before'.
X.TP
X.B Alarmnow
XContains the string `Time is now...'.
X.TP
X.B Already
XContains the string `Already editing %d %B %Y'
XI prefer to use `Already editing %e %B %Y'.
X.TP
X.B AlreadyWeekly
XContains the string `Already editing %A'.
X.SH "PANEL MAP"
X.PP
X.I Xcal
Xmakes extensive use of the resource manager.
XThe user needs to know the names of the various panels and widgets which
Xcomprise the application.
X.LP
X.EX
XXCal				Toplevel application
X	form			Form containing two buttons
X		today		Memo Command button
X		date		Strip Command button
X		mainHelp		Optional main help button
X.EE
X.LP
XThen we have various popups.
XThe Calendar Strip is:
X.EX
X"Mon Year"			the popup shell
X	Month			panel containing the strip
X		header		label containing month and year
X		action		form containing < quit > buttons 
X			back	command containing < - last month
X			quit	command containing exit button
X			next	command containing > - next month
X		help		command generating help
X	viewport			viewport permitting scrolling of the
X	data			data widget
X		"DDD"		form containing day button (lots of these)
X				these are named for the short days of the week
X			label	label containing dd DDD, day of the month
X				and day of the week
X			info	command containing the file data
X.EE
X.LP
XNote that each day button is named for the day of the week, so that
Xweekends can be highlighted specially using the standard resources.
X.LP
XThe weekly popup strip is:
X.EX
Xweekly				the popup shell
X	weekly			panel containing the strip
X		header		label containing the title
X		action		form containing quit and help
X			quit	command containing exit button
X			help	command generating help
X	viewport		viewport permitting scrolling of the
X	data			data widget
X		shortday	form containing days
X			label	label containing day of the week
X			info	command containing the file data
X.EE
X.LP
XThe Edit Window is:
X.EX
Xedit				the popup shell
X	panel			the panel inside the shell
X		title		the form containing the first line
X			quit	the exit button
X			save	the save button
X			help	the help button
X			date	the date string
X		text		the text widget for editing
X		
X.EE	
X.LP
XThe Help Window is:
X.EX
Xhelp				the popup shell
X	helpPanel			the panel inside the shell
X		helpForm		the form containing the title line
X			quit	the exit button
X		helpText		the text widget showing the information
X.EE
X.LP
XThe Alarm Window is:
X.EX
Xalarm				the popup shell
X	alarmPanel		the panel inside the shell
X		alarmForm	form for top line
X			alarmQuit	the exit button
X			alarmHold	the hold button
X			alarmTitle	the title on the alarm window
X		alarmText	the text widget for displaying
X.EE
X.LP
XThe Memo Window is:
X.EX
Xmemo				the popup shell
X	memoPanel		the panel inside the shell
X		title		Top line form widget
X			quit	the exit button
X			edit	edit button - edit today's info
X			help	the help button
X			date	display today's date
X		display		text from today's date file
X		weeklyMemo	form for the Memo title line
X			weeklyEdit	Edit button
X			weeklyTitle	Title area
X		display		text from today's weekly file
X		memoMiddle	Middle line form widget
X			save	Save button
X			memoTitle	text title of middle line
X		memoText	Text widget showing memo file
X.EE
X.LP
XThe Middle button date selection popup is:
X.EX
Xquestion				the popup shell
X	newdate			the dialog widget
X		ok		the OK button
X		cancel		the cancel button
X.EE
X.LP
XThe Right button exit selection popup is:
X.EX
Xquestion				the popup shell
X	exit			the dialog widget
X		yes		the yes button
X		no		the no button
X.EE
X.LP
XAn error is shown when a multiple attempts are made to edit the same day file.
X.EX
Xquestion				the popup shell
X	noedit			the dialog widget
X		ok		the OK button
X.EE
X.LP
XA dialog box is popped up when an attempt is made to exit from an editing
Xbox without saving the file.
X.EX
Xcheck				the dialog widget
X	yes			the yes button
X	no			the no button
X.EE
X.SH FILES
X.PP
X$HOME/Calendar/\(**
X.LP
X.TP "\w'xc<dd><Mon><Year>  'u"
Xxc<dd><Mon><Year>
XA data file is day, Month in three letter format and the year.
X.TP
Xxy<Year>
XA year directory.
X.TP
Xxw<Day>
XA data file for the weekly code, one per day.
X.TP
Xmemo
XThe memo file.
X.LP
XThe standard resource database can be found in /usr/lib/X11/app-defaults/Xcal.
XAssuming that this is where the system admin installed it.
X.PP
X.SH SEE ALSO
Xxrdb(1), xcalev(1), xcalpr(1), xcal_cal(1)
X.PP
X.SH BUGS
XThere should be some way of removing several edit windows from the screen
Xat once.
X.LP
XSetting an alarm 1 minute in the future may not work.
X.LP
XCountdown does not work in the early hours of the morning, if you have a
Xten minute countdown and an alarm set at 0005 \- then you will not get
Xwarning at 2325.
X.LP
XAlarms set at 0000 probably won't work.
X.SH AUTHOR
X.LP
XCopyright 1989,1990,1993 by Peter Collinson, Hillside Systems
XAll rights reserved.
X.PP
XThis product includes software developed by the University of
XCalifornia, Berkeley and its contributors.
X.PP
XAt one time, much of the
X.B xcalendar
Xprogram was plundered to create
X.B xcal ;
Xauthor is: Roman J. Budzianowski, MIT Project Athena
X.PP
XThanks to Ed Gould, Mt Xinu for the support for the
X.IR calendar (1)
Xprogram.
XThanks to Mark Majhor, Sequent for the basis of the alarm code.
XThanks to Rod Whitby, Austek Microsystems Pty. Ltd., Australia
Xfor the ideas of the Stick/Unpin code for alarms and for prompting
Xme to add the memo code.
XThanks to Miles O'Neal from Pencom for revising the help code to be
Xa little more `X', although this was later revised to use files.
X.LP
XThere are a number of other people who have sent in revisions, some I
Xhave used, some I have not.
XThanks anyway.
END_OF_FILE
if test 25369 -ne `wc -c <'xcal.man'`; then
    echo shar: \"'xcal.man'\" unpacked with wrong size!
fi
# end of 'xcal.man'
fi
if test -f 'xcal_edit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xcal_edit.c'\"
else
echo shar: Extracting \"'xcal_edit.c'\" \(27722 characters\)
sed "s/^X//" >'xcal_edit.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char    *sccsid = "@(#)xcal_edit.c	3.37 (Hillside Systems) 11/8/93";
Xstatic char    *copyright = "@(#)Copyright 1989,1990,1993 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 <pwd.h>
X#include <X11/Intrinsic.h>
X#include <X11/Xos.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#if defined(NeXT) || defined(mips)
X#include <sys/fcntl.h>
X#include <sys/dir.h>
X#include <sys/dirent.h>
X#else
X#include <dirent.h>
X#endif
X
X#define argLD(N,V) { XtSetArg(args[nargs], N, V); nargs++; }
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 */
X					/* exists */
X
Xstatic XtCallbackRec callbacks[] = {
X	{NULL, NULL},
X	{NULL, NULL}
X};
X#define ClearCallbacks() memset((caddr_t)callbacks, '\0', sizeof (callbacks))
X
X/*
X * Routine specs
X */	
Xstatic void	MakeMapStem();
Xstatic MeWrap  *NewMeWrap();
Xstatic MeWrap  *MeWrapSearch();
Xstatic void     DeRegisterMonth();
Xstatic Boolean  WriteCalendarFile();
Xstatic Boolean  WriteWeeklyFile();
Xstatic void     DeleteCalendarFile();
Xstatic int	EditCheck();
Xstatic void     SetAllButtons();
Xstatic void     TextChanged();
Xstatic void	UpdateDayDetails();
Xstatic void     FinishEditing();
Xstatic void     CleanEditPanel();
Xstatic void     CheckExit();
Xstatic void     CheckDia();
Xstatic void     YesCheck();
Xstatic void     NoCheck();
Xstatic int      DayMatch();
Xstatic void	SaveEdits();
Xvoid            StartDayEditor();
Xvoid            Fatal();
X
X
X
X/*
X * Fire up the month entry environment called once
X */
Xvoid
XInitMonthEntries()
X{
X	if (MapStem == NULL)
X		MakeMapStem();
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 *	Find the base of the Calendar structure
X */
Xstatic void
XMakeMapStem()
X{	
X	char            buf[BUFSIZ];
X	struct passwd	*pw;
X
X	if (appResources.otheruser) {
X		/* someone else */
X		pw = getpwnam(appResources.otheruser);
X		if (pw == NULL)
X			Fatal("Cannot get password details for %s\n", appResources.otheruser);
X	} else {
X		pw = getpwuid(getuid());
X		if (pw == NULL)
X			Fatal("Cannot get password details for YOU!\n");
X	}
X	(void) sprintf(buf, "%s/%s", pw->pw_dir, appResources.directory);
X	MapStem = XtNewString(buf);
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	struct dirent  *dp;
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	mw->mw_me.me_type = ME_MONTHLY;
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	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	while ((dp = readdir(dirp)) != NULL) {
X
X		switch (strlen(dp->d_name)) {
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
X				 * our time at the top
X				 * level - rejig things
X			         * 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()
X{
X	MeWrap         *mw;
X	int             da;
X	DIR            *dirp;
X	struct dirent  *dp;
X
X	if ((mw = MeWrapSearch(0, 0)) == NULL)
X		mw = NewMeWrap(0, 0);
X	mw->mw_me.me_type = ME_WEEKLY;
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	while ((dp = readdir(dirp)) != NULL) {
X		if (dp->d_name[0] == 'x' &&
X		    dp->d_name[1] == 'w' &&
X		    ((da = DayMatch(&dp->d_name[2])) != -1)) {
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	static MeWrap	zerow;
X	
X	mw = (MeWrap *) XtMalloc(sizeof(MeWrap));
X	*mw = zerow;
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 Return a pointer to an instance structure
X * so it can be filled 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
X				mw->mw_list = ins->i_next;
X			XtFree((char *) 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		if (MyCalendar)
X			Fatal("Cannot open: %s for reading", file);
X		else
X			return(XtNewString(appResources.private));
X	}	
X	if (fstat(fd, &fsb) < 0)
X		Fatal("Cannot fstat %s", file);
X
X	if (fsb.st_size == 0) {
X		if (MyCalendar)
X			(void) unlink(file);
X		close(fd);
X		return (NULL);
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 which are needed
X * Return True if 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. However, we
X	 * would like to put any new data into subdirectories named for the
X	 * year unless we are compatible with xcalendar
X	 */
X	fname[0] = '\0';
X	if (appResources.calCompat == False && mw->mw_useTopDir == False) {
X		/*
X		 * we have no data in the top directory
X		 * so let's create the directory name
X		 */
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	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		/*
X		 * we have no data in the top directory 
X		 * so let's create the directory name
X		 */
X		(void) sprintf(fname, "xy%d", mw->mw_year);
X
X		if (access(fname, F_OK) < 0)
X			return;
X		strcat(fname, "/");
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		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 after the edit
X */
X/* ARGSUSED */
Xvoid
XStartEditing(w, da, but)
X	Widget          w;
X	Date           *da;
X	Widget		but;
X{
X	register MeWrap *mw;
X	register EditLine *ed;
X	static EditLine	zeroe;
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 editing this day
X	 */
X	if (EditCheck(w, mw, da))
X		return;
X	/*
X	 * Things are looking OK
X	 * Create a new editing record
X	 */
X	ed = (EditLine *) XtMalloc(sizeof(EditLine));
X	*ed = zeroe;
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	} 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 then
X	 * 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 month
X	 */
X	StartDayEditor(mw, da, but);
X}
X
X/*
X *	See if we are editing a day already
X *	complain and return 1 if we are
X *	return 0 if not
X */
Xstatic int
XEditCheck(w, mw, da)
X	Widget		w;
X	MeWrap		*mw;
X	Date		*da;
X{
X	register EditLine *ed;
X
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) {	/* we are! */
X			/* Complain via a popup */
X			switch (StripType(mw)) {
X			case ME_MONTHLY:
X				NoEditIsPossible(w, da);
X				break;
X			case ME_WEEKLY:
X				NoDayEditIsPossible(w, da);
X				break;
X			}
X			return 1;
X		}
X	}
X	return 0;
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 Modelled on xcalendar.c
X */
Xvoid
XStartDayEditor(mw, da, but)
X	register MeWrap *mw;
X	register Date  *da;
X	Widget but;
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[BUFSIZ];
X	void            EditHelp();
X	
X	ed->ed_popup = XtCreatePopupShell("edit", topLevelShellWidgetClass, toplevel, NULL, 0);
X
X	if (but && XtIsSubclass(but, commandWidgetClass))
X		ButtonOff(but, ed->ed_popup);
X
X	/*
X	 * Create the title line - which is a form containing buttons and a
X	 * date label
X	 */
X	et = XtCreateManagedWidget("panel", panedWidgetClass, ed->ed_popup, NULL, 0);
X
X	nargs = 0;
X	argLD(XtNshowGrip, False);
X	argLD(XtNskipAdjust, True);
X	argLD(XtNdefaultDistance, 1);
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	argLD(XtNcallback, callbacks);
X	argLD(XtNfromHoriz, NULL);
X	argLD(XtNleft, XtChainLeft);
X	argLD(XtNright, XtChainLeft);
X	lw = ed->ed_quit = XtCreateManagedWidget("quit", commandWidgetClass, frame, args, nargs);
X
X	/*
X	 * Take label "save" from resources
X	 */
X	if (MyCalendar) {
X		callbacks[0].callback = SaveEdits;
X		callbacks[0].closure = (caddr_t) ed;
X		nargs = 0;
X		argLD(XtNcallback, callbacks);
X		argLD(XtNfromHoriz, ed->ed_quit);
X		argLD(XtNleft, XtChainLeft);
X		argLD(XtNright, XtChainLeft);
X		argLD(XtNsensitive, False);
X		lw = ed->ed_save = XtCreateManagedWidget("save", commandWidgetClass, frame, args, nargs);
X		
X	}	
X	if (appResources.giveHelp) {
X		/*
X		 * Take label "help" from resources
X		 */
X		callbacks[0].callback = EditHelp;
X		callbacks[0].closure = (caddr_t) 0;
X		nargs = 0;
X		argLD(XtNcallback, callbacks);
X		argLD(XtNfromHoriz, lw);
X		argLD(XtNleft, XtChainLeft);
X		argLD(XtNright, XtChainLeft);
X		lw = XtCreateManagedWidget("help", commandWidgetClass, frame, args, nargs);
X	}
X	switch (StripType(mw)) {
X	case ME_MONTHLY:
X		FmtDate(da, buf, sizeof buf, appResources.editfmt);
X		break;
X	case ME_WEEKLY:
X		(void) strcpy(buf, appResources.day[da->day]);
X		break;
X	}
X	nargs = 0;
X	argLD(XtNlabel, buf);
X	argLD(XtNborderWidth, 0);
X	argLD(XtNfromHoriz, lw);
X	argLD(XtNfromVert, NULL);
X	argLD(XtNvertDistance, 2);
X	argLD(XtNleft, XtChainLeft);
X	argLD(XtNright, XtChainRight);
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	argLD(XtNshowGrip, False);
X	argLD(XtNstring, ed->ed_data);
X	argLD(XtNeditType, XawtextEdit);
X	argLD(XtNlength, ed->ed_size);
X	argLD(XtNuseStringInPlace, True);
X	argLD(XtNcallback, callbacks);
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	if (MyCalendar)
X		XtSetSensitive(ed->ed_save, True);
X}
X
X
X/* ARGSUSED */
Xstatic void
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 MeWrap *mw;
X	register Cardinal day;
X
X	mw = ed->ed_meWrap;
X	day = ed->ed_day;
X
X	switch (StripType(mw)) {
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	 * Update the visual image
X	 */
X	UpdateDayDetails(mw, day);
X	XtSetSensitive(ed->ed_save, False);
X}
X
Xstatic void
XUpdateDayDetails(mw, day)
X	MeWrap		*mw;
X	Cardinal	day;
X{
X	Instance	*ins;
X	int		nargs;
X	Arg             args[3];
X
X	XtSetArg(args[0], XtNlabel, mw->mw_have[day]);
X	for (ins = mw->mw_list; ins; ins = ins->i_next) {
X		nargs = 1;
X		if (*mw->mw_have[day] == '\0') {
X			argLD(XtNforeground, ins->i_col.fg);
X			argLD(XtNbackground, ins->i_col.bg);
X		}
X		XtSetValues(ins->i_day_info[day], args, nargs);
X	}
X
X	/*
X	 * worry about updating the memo system
X	 */
X
X	switch (StripType(mw)) {
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	XtSetSensitive(ed->ed_quit, False);
X	if (MyCalendar)
X		XtSetSensitive(ed->ed_save, False);
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	} else 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
X				mw->mw_ed = ed->ed_next;
X			break;
X		}
X	}
X	XtFree((char *) 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, NULL);
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	XtSetSensitive(ed->ed_quit, False);
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	XtAppError(appContext, buf);
X	/* NOTREACHED */
X}
X
X/*
X * These routines used to insert text into a file
X * from the middle button press.
X * Code called from xcal_strip.c
X * The routine is responsible for freeing the text string
X */
Xvoid
XAppendText(w, da, txt)
X	Widget		w;
X	Date		*da;
X	String		txt;
X{
X	MeWrap		*mw;
X	Cardinal	len;
X	Cardinal	srclen;
X	String		newstr;
X
X	if ((mw = MeWrapSearch(da->year, da->month)) == NULL)
X		mw = NewMeWrap();	/* shouldn`t happen */
X
X	if (EditCheck(w, mw, da))
X		return;
X
X	/*
X	 * if we have some text already, we must append the new text to it
X	 */
X	if (mw->mw_have[da->day]) {
X		/*
X		 * size of new string is sum of previous two
X		 * plus two for the nulls at the end of the string
X		 * plus one because we made need to insert a newline
X		 * after the old text
X		 */
X		srclen = strlen(mw->mw_have[da->day]);
X		if (srclen) {
X			len = srclen + strlen(txt) +3;
X			newstr = XtMalloc(len);
X			strcpy(newstr, mw->mw_have[da->day]);
X			if (newstr[srclen] == '\0') {
X				newstr[srclen++] = '\n';
X				newstr[srclen] = '\0';
X			}
X			strcat(newstr, txt);
X			XtFree(txt);
X			txt = newstr;
X		}
X	}
X
X	switch (StripType(mw)) {
X	case ME_MONTHLY:
X		if (WriteCalendarFile(mw, da->day, txt) == False)
X			return;
X		break;
X	case ME_WEEKLY:
X		if (WriteWeeklyFile(mw, da->day, txt) == False)
X			return;
X		break;
X	}
X	/*
X	 * Otherwise change the displayed string
X	 */
X	if (mw->mw_have[da->day])
X		XtFree(mw->mw_have[da->day]);
X	mw->mw_have[da->day] = txt;
X
X	UpdateDayDetails(mw, da->day);
X}
END_OF_FILE
if test 27722 -ne `wc -c <'xcal_edit.c'`; then
    echo shar: \"'xcal_edit.c'\" unpacked with wrong size!
fi
# end of 'xcal_edit.c'
fi
echo shar: End of archive 8 \(of 8\).
cp /dev/null ark8isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
