Here's a Script for Importing HyperCard Calendars into iCal or BusyCal

Greetings, folks!
This may be of little (if any) use to others, given the age of HyperCard, but it is a script for converting a DIFfersifier generated export of a HyperCard calendar into a “.ics” file that can be imported into iCal or BusyCal. Dave Riggle and John Chaffee’s incredible work on BusyCal inspired me to do what I’ve been putting off for over a decade. :wink: Wisdom gained from MacScripter was plundered without shame.
Here it is:

(*
This script assumes DIFfersifier has been used to generate the comma-delimited text on a per-week basis and is replacing returns with vertical tabs (ASCII character 11). Open the resulting file in BBEdit (though Text Wrangler may be up to it!) and run this script. When the script is done, save it as an ".ics" file. Double-clicking the file will open iCal/BusyCal and import it. Put it in a new calendar for review.
NOTE: -- multi-event dates in HyperCard adding \",\" is an error due to changing the TID and not resetting it afterward. Reboot may be necessary; it may just require quitting the AppleScript editor.
*)

global theIndex, theTIDs, trimCharacters, theDates, prevWeeksMonth, theMonth, theDayNumber, theLastDay, startDate, thisWeeksMonth, theExportWeek, errorCount, theYear

set theTIDs to AppleScript's text item delimiters
set theLastDay to {{"0131", "0201"}, {"0228", "0301"}, {"0229", "0301"}, {"0331", "0401"}, {"0430", "0501"}, {"0531", "0601"}, {"0630", "0701"}, {"0731", "0801"}, {"0831", "0901"}, {"0930", "1001"}, {"1031", "1101"}, {"1130", "1201"}, {"1231", "0101"}} -- this compensates for end-of-month issues
set trimCharacters to {" ", tab, return, ASCII character 0, ASCII character 10, ASCII character 11}
set theCalendar to ""

tell application "BBEdit"
	-- before anything else, replace multiple returns to eliminate errant events in any given day, as they won't be stripped by trim()
	replace ((ASCII character 11) & (ASCII character 11) & "+") using (ASCII character 11) searching in text 1 of text document 1 options {search mode:grep, starting at top:true}
	
	-- establish the field headings index and determine the version of HyperCard that was used
	set theIndex to line 1 of text 1 of text document 1 as text -- this establishes the numerical index of days and dates
	
	-- if the calendar is from version 1 of HyperCard's calendar
	if theIndex is "wee,mon,tue,wed,thu,fri,Month,WeekNumber,monday,tuesday,wednesday,thursday,friday,weekend" then
		set theIndex to "HC1"
		-- if the calendar is from version 2 of HyperCard's calendar
	else if theIndex is "Mon,Tue,Wed,Thu,Fri,Sat,Sun,Month,WeekNumber,weekday1,weekday2,weekday3,weekday4,weekday5,weekday6,weekday7,weekSecs" then
		set theIndex to "HC2"
		-- also establish the initial month number for the card, i.e. week, as HyperCard 2 will often title a week with the coming month
		set theList to characters 2 thru -2 of line 2 of text 1 of text document 1 as text -- consolidate the data
		set AppleScript's text item delimiters to "\",\""
		set theMonth to word 2 of (item 8 of the text items of theList)
		set AppleScript's text item delimiters to theTIDs -- restore the default
		set prevWeeksMonth to ((offset of theMonth's text 1 thru 3 in " JanFebMarAprMayJunJulAugSepOctNovDec") div 3 + 1)
		set errorCount to 0
	else
		say "the list headings do not match, please adjust the index"
		return
	end if
	
	######## Here We Set the Range and Process the Data ########
	-- this repeat goes through each line of the comma-delimited text file generated by DIFfersifier, which is by week
	repeat with weekNumber from 2 to ((the number of lines of text 1 of text document 1) - 1) -- the last line is a return
		my eachWeek(weekNumber)
		set theCalendar to theCalendar & theExportWeek
	end repeat
	############################################
	
	-- prepare the data for importing into iCal/BusyCal
	set theCalendar to "BEGIN:VCALENDAR" & return & theCalendar & "END:VCALENDAR" -- theCalendar ends with a return
	make new text window with properties {contents:theCalendar}
	-- strip out multiple spaces
	replace "  +" using " " searching in text 1 of text document 1 options {search mode:grep, starting at top:true}
	-- strip out any empty entries
	replace "BEGIN:VJOURNAL" & return & "DTSTART;VALUE=DATE:(\\d+)" & return & "DTEND;VALUE=DATE:(\\d+)" & return & "SUMMARY:" & return & "END:VJOURNAL" & return using "" searching in text 1 of text document 1 options {search mode:grep, case sensitive:true, starting at top:true}
	activate
	select insertion point before character 1 of line 1 of text window 1 -- scroll to the top of the window
	if theIndex is "HC2" then say "there were " & errorCount & " date errors" -- where the month name was not for the first day
end tell


---- The Handlers ----

-- process each week, one week at a time
on eachWeek(weekNumber)
	-- strip out the opening and closing quotes as the text item delimiters substitution won't do it
	tell application "BBEdit" to set theList to characters 2 thru -2 of line weekNumber of text 1 of text document 1 as text
	
	-- create two corresponding lists with matching day/date references
	set AppleScript's text item delimiters to "\",\""
	#### the following is for early HyperCard calendars ####
	if theIndex is "HC1" then
		-- "text items of" to make it a list, the first six are: wee,mon,tue,wed,thu,fri -- this is the event text for the week
		set theEvents to items 2 thru 3 of the text items of theList & item 1 of the text items of theList
		-- these are the date number fields, and is appending the year and month text for the week
		set theDates to items 9 thru -1 of the text items of theList & item 7 of the text items of theList
		-- split out the weekend, and append the year and month
		set theDates to items 1 thru 5 of theDates & word 1 of item 6 of theDates & word 2 of item 6 of theDates & item 7 of theDates
		set daysInWeek to 6
		#### the following is for HyperCard 2 (or so  ;-)  ) calendars ####
	else if theIndex is "HC2" then
		-- "text items of" to make it a list, the first seven are: Mon,Tue,Wed,Thu,Fri,Sat,Sun -- this is the event text for the week
		set theEvents to items 1 thru 7 of the text items of theList
		-- these are the date number fields, and is appending the year and month text for the week
		set theDates to items 1 thru 8 of (items 10 thru -2 of the text items of theList & item 8 of the text items of theList)
		set daysInWeek to 7
	end if
	set AppleScript's text item delimiters to theTIDs -- restore the default
	set theExportWeek to "" as text
	
	-- ensure that the day numbers are two digits
	repeat with i from 1 to 7
		if the number of characters of item i of theDates = 1 then set item i of theDates to "0" & item i of theDates
	end repeat
	
	repeat with d from 1 to daysInWeek -- the number of items of theEvents
		set e to ""
		set startDate to ""
		set endDate to ""
		set theEvent to item d of theEvents
		if the number of characters of theEvent > 0 then
			set theEvent to trim(trimCharacters, theEvent)
			
			-- if there are multiple events in a day
			if theEvent contains (ASCII character 11) then
				set AppleScript's text item delimiters to ASCII character 11
				set splitDay to text items of theEvent -- not text of, text items of
				set AppleScript's text item delimiters to theTIDs -- restore the default
				repeat with e from 1 to the number of items of splitDay
					set theEvent to item e of splitDay
					if the number of characters of theEvent > 0 then
						set theEvent to trim(trimCharacters, theEvent)
						set item e of splitDay to theEvent
						-- create the export data
						set startDate to my processStartDate(d, startDate)
						set endDate to my processEndDate(endDate)
						set theEventExport to ("BEGIN:VJOURNAL" & return & "DTSTART;VALUE=DATE:" & startDate & return & "DTEND;VALUE=DATE:" & endDate & return & "SUMMARY:" & theEvent & return & "END:VJOURNAL" & return)
						set item e of splitDay to theEventExport
					end if
				end repeat
				set item d of theEvents to splitDay
			else -- if there is only one event in the day
				-- create the export data
				set startDate to my processStartDate(d, startDate)
				set endDate to my processEndDate(endDate)
				set theDayExport to ("BEGIN:VJOURNAL" & return & "DTSTART;VALUE=DATE:" & startDate & return & "DTEND;VALUE=DATE:" & endDate & return & "SUMMARY:" & theEvent & return & "END:VJOURNAL" & return)
				set item d of theEvents to theDayExport
			end if
		end if
		if item d of theEvents is not "" then set theExportWeek to (theExportWeek & item d of theEvents)
	end repeat
	if theIndex is "HC2" then set prevWeeksMonth to thisWeeksMonth
	return theExportWeek
end eachWeek

on processStartDate(d, startDate)
	-- generate the day number
	set theDayNumber to item d of theDates
	
	-- generate the month number
	set theMonth to ((offset of (word 2 of item 8 of theDates)'s text 1 thru 3 in " JanFebMarAprMayJunJulAugSepOctNovDec") div 3 + 1)
	if theIndex is "HC2" then -- given that the week's month may not correspond to the month of the first day of the week
		set thisWeeksMonth to theMonth as number
		if ((prevWeeksMonth < theMonth) and (theDayNumber > 0)) then
			set errorCount to errorCount + 1
			set theMonth to (theMonth - 1)
		end if
	end if
	-- ensure that the month numbers are two digits
	if the number of characters of (theMonth as text) = 1 then set theMonth to "0" & theMonth as text
	
	-- generate the year
	set theYear to word 1 of item 8 of theDates
	
	-- generate the full date
	-- if the day number is less than the opening-of-the-week day number, increase the month number
	if theDayNumber < item 1 of theDates then
		if theMonth = 12 then -- if it is December then make it January and make it a new year
			set theMonth to "01"
			set theYear to theYear + 1
		else -- just increasee the month number
			set theMonth to theMonth + 1
			if the number of characters of (theMonth as text) = 1 then set theMonth to "0" & theMonth as text
		end if
	end if
	set startDate to (theYear as text) & theMonth & theDayNumber
	return startDate
end processStartDate

on processEndDate(endDate)
	-- this calculates end-of-month-and-year dates for the end-of-event date, i.e., the next day
	set beginDate to (theMonth as text) & (theDayNumber as text) as number
	if (beginDate = item 1 of item 13 of theLastDay as number) then -- if it is December 31st
		set endDate to (theYear + 1 as text) & (item 2 of item 13 of theLastDay)
	else
		repeat with i from 1 to 12 -- I have two enties for February  ;-)
			if (beginDate = item 1 of item i of theLastDay as number) then
				set endDate to theYear & (item 2 of item i of theLastDay)
				exit repeat
			else
				set endDate to ((startDate + 1) as number)
			end if
		end repeat
	end if
	return endDate
end processEndDate

-- trim the text
on trim(trimCharacters, theEvent)
	-- remove extraneous spaces, returns, etc.
	set isText to false
	repeat with c from 1 to the number of characters in theEvent
		if character c of theEvent is not in trimCharacters then -- if it is not just empty space
			set isText to true
			exit repeat
		end if
	end repeat
	if isText is true then
		repeat until first character of theEvent is not in trimCharacters
			set theEvent to text 2 thru -1 of theEvent
		end repeat
		repeat until last character of theEvent is not in trimCharacters
			set theEvent to text 1 thru -2 of theEvent
		end repeat
	else
		set theEvent to ""
	end if
	return theEvent
end trim

Model: 2.33GHz MBPC2D
Browser: Google Chrome 6.0.472.62
Operating System: Mac OS X (10.6)