mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-17 06:48:47 +02:00
362 lines
10 KiB
Tcl
Executable File
362 lines
10 KiB
Tcl
Executable File
#!/bin/sh
|
|
# -*-Mode: TCL;-*-
|
|
|
|
#--------------------------------------------------------------
|
|
# cm2rem.tcl
|
|
#
|
|
# A cheesy Tcl script to convert Sun's "cm" calendar manager
|
|
# files (version 3 only) to Remind format.
|
|
#
|
|
# This file is part of REMIND.
|
|
# Copyright (C) 1992-1998 by David F. Skoll
|
|
# Copyright (C) 1999 by Roaring Penguin Software Inc.
|
|
#
|
|
#--------------------------------------------------------------
|
|
|
|
# $Id: cm2rem.tcl,v 1.2 1999-08-30 16:28:01 dfs Exp $
|
|
|
|
# the next line restarts using tclsh \
|
|
exec tclsh "$0" "$@"
|
|
|
|
set i 0
|
|
foreach month {January February March April May June
|
|
July August September October November December} {
|
|
incr i
|
|
set MonthNum($month) $i
|
|
set FullMonth([string range $month 0 2]) $month
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: convertParens
|
|
# %ARGUMENTS:
|
|
# line -- a line read from a cm file
|
|
# %RETURNS:
|
|
# A new line with all ( and ) outside quotes converted to { and }.
|
|
# This cheap trick allows us to use Tcl's built-in list manipulation
|
|
# functions to munge the line.
|
|
#***********************************************************************
|
|
proc convertParens { line } {
|
|
# Convert all ( and ) to { and } unless they are inside a quoted
|
|
# string
|
|
set out ""
|
|
set len [string length $line]
|
|
set inQuotes 0
|
|
for {set i 0} {$i < $len} {incr i} {
|
|
set char [string range $line $i $i]
|
|
if {$char == "\\" && $inQuotes} {
|
|
append out $char
|
|
incr i
|
|
set char [string range $line $i $i]
|
|
append out $char
|
|
continue
|
|
}
|
|
|
|
if {$char == "(" && !$inQuotes} {
|
|
set char \{
|
|
}
|
|
|
|
if {$char == ")" && !$inQuotes} {
|
|
set char \}
|
|
}
|
|
|
|
if {$char == "\""} {
|
|
set inQuotes [expr !$inQuotes]
|
|
}
|
|
|
|
append out $char
|
|
}
|
|
return $out
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: processLine
|
|
# %ARGUMENTS:
|
|
# line -- a line read from a cm file
|
|
# %RETURNS:
|
|
# Nothing
|
|
# %DESCRIPTION:
|
|
# Processes a single line from the file, possibly writing a reminder
|
|
# in Remind format to stdout
|
|
#***********************************************************************
|
|
proc processLine { line } {
|
|
global Attributes
|
|
global FullMonth
|
|
|
|
catch {unset Attributes}
|
|
|
|
# Only convert lines which start with "(add"
|
|
if {[string range $line 0 3] != "(add"} {
|
|
return
|
|
}
|
|
set line [convertParens $line]
|
|
# Convert it to a list. CAREFUL: Potential security problem if
|
|
# $line contains something nasty.
|
|
|
|
eval set line $line
|
|
|
|
set Attributes(body) ""
|
|
foreach {key val} $line {
|
|
switch -exact -- $key {
|
|
"add" {
|
|
set Attributes(date) $val
|
|
}
|
|
"what:" {
|
|
append Attributes(body) $val
|
|
}
|
|
"details:" {
|
|
append Attributes(body) $val
|
|
}
|
|
"duration:" {
|
|
set Attributes(duration) $val
|
|
}
|
|
"period:" {
|
|
set Attributes(period) $val
|
|
}
|
|
"ntimes:" {
|
|
set Attributes(ntimes) $val
|
|
}
|
|
"attributes:" {
|
|
set Attributes(action) $val
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if {[info exists Attributes(action)]} {
|
|
# Nuke quotes and commas in action
|
|
regsub -all {[,\"]} $Attributes(action) { } Attributes(action)
|
|
|
|
# Add spaces to pairs
|
|
regsub -all \}\{ $Attributes(action) \}\ \{ Attributes(action)
|
|
|
|
# Add another pair of brackets to make a proper list
|
|
set Attributes(action) "{$Attributes(action)}"
|
|
|
|
# Convert to a real Tcl list
|
|
eval set Attributes(action) $Attributes(action)
|
|
}
|
|
# Split out date into month, day, year, time parts
|
|
scan $Attributes(date) "%s%s%s%s%s" wkday month day time year
|
|
set time [string range $time 0 4]
|
|
set Attributes(wkday) $wkday
|
|
set Attributes(month) $FullMonth($month)
|
|
set Attributes(day) $day
|
|
set Attributes(time) $time
|
|
set Attributes(year) $year
|
|
|
|
# Convert newlines in body to spaces
|
|
set body $Attributes(body)
|
|
regsub -all "\n" $body " " body
|
|
|
|
# TODO: Escape BODY to get rid of [] chars.
|
|
set Attributes(body) $body
|
|
|
|
# Convert to Reminder format
|
|
convertReminder
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: convertReminder
|
|
# %ARGUMENTS:
|
|
# None -- uses global Attributes variable which must be filled in
|
|
# %RETURNS:
|
|
# Nothing
|
|
# %DESCRIPTION:
|
|
# Converts a reminder to Remind format.
|
|
#***********************************************************************
|
|
proc convertReminder {} {
|
|
global Attributes
|
|
switch -exact $Attributes(period) {
|
|
single { convertSingleReminder }
|
|
daily { convertDailyReminder }
|
|
weekly { convertWeeklyReminder }
|
|
monthly { convertMonthlyReminder }
|
|
yearly { convertYearlyReminder }
|
|
default {
|
|
puts "\# Unable to convert reminder with period $Attributes(period)"
|
|
puts "\# Body is: $Attributes(body)"
|
|
}
|
|
}
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: convertSingleReminder
|
|
# %ARGUMENTS:
|
|
# None -- uses global Attributes variable which must be filled in
|
|
# %RETURNS:
|
|
# Nothing
|
|
# %DESCRIPTION:
|
|
# Converts a reminder with "single" period to Remind format.
|
|
#***********************************************************************
|
|
proc convertSingleReminder {} {
|
|
global Attributes
|
|
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) [at][duration]MSG $Attributes(body)"
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: convertDailyReminder
|
|
# %ARGUMENTS:
|
|
# None -- uses global Attributes variable which must be filled in
|
|
# %RETURNS:
|
|
# Nothing
|
|
# %DESCRIPTION:
|
|
# Converts a reminder with "daily" period to Remind format.
|
|
#***********************************************************************
|
|
proc convertDailyReminder {} {
|
|
global Attributes
|
|
set ntimes [expr $Attributes(ntimes) - 1]
|
|
if {$ntimes <= 1} {
|
|
convertSingleReminder
|
|
return
|
|
}
|
|
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) $ntimes]
|
|
|
|
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *1 [at][duration]UNTIL $until MSG $Attributes(body)"
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: convertWeeklyReminder
|
|
# %ARGUMENTS:
|
|
# None -- uses global Attributes variable which must be filled in
|
|
# %RETURNS:
|
|
# Nothing
|
|
# %DESCRIPTION:
|
|
# Converts a reminder with "daily" period to Remind format.
|
|
#***********************************************************************
|
|
proc convertWeeklyReminder {} {
|
|
global Attributes
|
|
set ntimes [expr $Attributes(ntimes) - 1]
|
|
if {$ntimes <= 1} {
|
|
convertSingleReminder
|
|
return
|
|
}
|
|
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 7]]
|
|
|
|
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *7 [at][duration]UNTIL $until MSG $Attributes(body)"
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: convertMonthlyReminder
|
|
# %ARGUMENTS:
|
|
# None -- uses global Attributes variable which must be filled in
|
|
# %RETURNS:
|
|
# Nothing
|
|
# %DESCRIPTION:
|
|
# Converts a reminder with "monthly" period to Remind format.
|
|
#***********************************************************************
|
|
proc convertMonthlyReminder {} {
|
|
global Attributes
|
|
set ntimes [expr $Attributes(ntimes) - 1]
|
|
if {$ntimes <= 1} {
|
|
convertSingleReminder
|
|
return
|
|
}
|
|
|
|
# If repetition > 1000, it's infinite
|
|
if {$ntimes > 1000} {
|
|
puts "REM $Attributes(day) [at][duration]MSG $Attributes(body)"
|
|
return
|
|
}
|
|
|
|
### UNTIL date is fudged!
|
|
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 30]]
|
|
|
|
puts "REM $Attributes(day) [at][duration]UNTIL $until MSG $Attributes(body)"
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: convertYearlyReminder
|
|
# %ARGUMENTS:
|
|
# None -- uses global Attributes variable which must be filled in
|
|
# %RETURNS:
|
|
# Nothing
|
|
# %DESCRIPTION:
|
|
# Converts a reminder with "yearly" period to Remind format.
|
|
#***********************************************************************
|
|
proc convertYearlyReminder {} {
|
|
global Attributes
|
|
|
|
# No special handling of ntimes et al.
|
|
puts "REM $Attributes(day) $Attributes(month) [at][duration]MSG $Attributes(body)"
|
|
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: at
|
|
# %ARGUMENTS:
|
|
# None -- uses Attributes global variable
|
|
# %RETURNS:
|
|
# A string providing the correct AT clause for a timed reminder.
|
|
#***********************************************************************
|
|
proc at {} {
|
|
global Attributes
|
|
if {![info exists Attributes(time)]} {
|
|
return ""
|
|
}
|
|
if {"$Attributes(time)" == ""} {
|
|
return ""
|
|
}
|
|
|
|
return "AT $Attributes(time) "
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: duration
|
|
# %ARGUMENTS:
|
|
# None -- uses Attributes global variable
|
|
# %RETURNS:
|
|
# A string providing the correct DURATION clause for a timed reminder.
|
|
#***********************************************************************
|
|
proc duration {} {
|
|
global Attributes
|
|
if {![info exists Attributes(duration)]} {
|
|
return ""
|
|
}
|
|
if {"$Attributes(duration)" == ""} {
|
|
return ""
|
|
}
|
|
set h [expr $Attributes(duration) / 3600]
|
|
set remainder [expr $Attributes(duration) - $h*3600]
|
|
set m [expr $remainder / 60]
|
|
return "DURATION [format "%d:%02d " $h $m]"
|
|
}
|
|
|
|
#***********************************************************************
|
|
# %PROCEDURE: getUntilDate
|
|
# %ARGUMENTS:
|
|
# day, month, year -- a date
|
|
# days -- number of days to add to date
|
|
# %RETURNS:
|
|
# The date which is "days" later than supplied date in a correct UNTIL
|
|
# format.
|
|
#***********************************************************************
|
|
proc getUntilDate { day month year days } {
|
|
global RemindPipe
|
|
global MonthNum
|
|
set date "'$year/$MonthNum($month)/$day'"
|
|
puts $RemindPipe "MSG \[trigger($date + $days)\]%"
|
|
puts $RemindPipe "flush"
|
|
flush $RemindPipe
|
|
gets $RemindPipe line
|
|
return $line
|
|
}
|
|
|
|
catch {wm withdraw .}
|
|
# Start a Remind process to issue reminders
|
|
if {[catch {set RemindPipe [open "|remind -" "r+"]} err]} {
|
|
puts stderr "Error: Cannot run Remind: $err"
|
|
exit 1
|
|
}
|
|
|
|
puts $RemindPipe "banner %"
|
|
flush $RemindPipe
|
|
|
|
# Write some blurb
|
|
puts "\# Reminder file converted from \"cm\" data by cm2rem.tcl"
|
|
puts ""
|
|
|
|
while {[gets stdin line] >= 0} {
|
|
processLine $line
|
|
}
|
|
exit 0
|