[comp.lang.rexx] More ARexx scripts...

mwm@violet.berkeley.edu (Mike (I'll think of something yet) Meyer) (05/31/89)

Here's yet more ARexx scripts, since someone called for them. This is
a shar file with various small tools in it. You'll find:

- an exec to create a small window with a one-month calendar in it, defaulting
	to the current month

- an exec to put an arbitrary file, or standard input, into a window

- an exec to delete the window used by the two above tools.

N.B. both post and month use the RexxArpLib window. You no got
RexxArpLib, they no work.

- A qad Unix-like "foreach." No variables, just maps % to each
	filename. Uses C-\ to end the command list.

Many of these use ExecIO, which comes with WShell. All I do is read a
file or standard input into a variable, with "execio <magic> stem
varname.".  You can get the same effect by opening the file (if it's
indeed a file), and reading lines into varname.#, one line per
variable, starting with 1. Finally, load varname.0 with the number of
lines read. ExecIO is just an order of magnitude faster, is all.

	<mike


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	month.rexx
#	post.rexx
#	nomsg.rexx
#	expand.rexx
#	foreach.rexx
#	man.rexx
# This archive created: Tue May 30 20:23:25 1989
cat << \SHAR_EOF > month.rexx
/*
 * cal - open a month's calendar on the workbench screen for the
 *	user.
 *
 * usage: cal [month [year]]
 *
 * If no args are given, use the current month & year.
 * 
 * Month may be either a month name (only the first three characters
 * are used), or the number of the month.
 *
 * Year is the year of the christian era. If the length is exactly two
 * characters, then a '19' is prepended to it. So '9' is the year 9,
 * '09' is the year 1909; '34' is the year 1934, 034 is the year 34.
 *
 * The calendar presented is correct for England & it's colonies for
 * periods when there was more than one calendar in general use. For
 * grins, try 'cal 9 1752'
 */

arg month year .

/* Set up the months table - from names to numbers, */
months. = 0
months.jan = 1
months.feb = 2
months.mar = 3
months.apr = 4
months.may = 5
months.jun = 6
months.jul = 7
months.aug = 8
months.sep = 9
months.oct = 10
months.nov = 11
months.dec = 12

/* and now from numbers to days/month & print names */
months.1 = 'January'
months.1.days = 31
months.2 = 'February'
months.2.days = 1	/* Fixed later */
months.3 = 'March'
months.3.days = 31
months.4 = 'April'
months.4.days = 30
months.5 = 'May'
months.5.days = 31
months.6 = 'June'
months.6.days = 30
months.7 = 'July'
months.7.days = 31
months.8 = 'August'
months.8.days = 31
months.9 = 'September'
months.9.days = 30
months.10 = 'October'
months.10.days = 31
months.11 = 'November'
months.11.days = 30
months.12 = 'December'
months.12.days = 31		/* Not needed, but here for completeness */

/* Get the current date for later use*/
parse value date('Normal') with . mymonth myyear

/* Get a month to work with */
if datatype(month, 'Numeric') then mymonth = month
else do
	if month ~= "" then mymonth = month
	mymonth = upper(left(mymonth, 3))
	mymonth = months.mymonth
	end

if months.mymonth.days = 0 then do
	say "Month must be a month name or a number from 1 to 12, not" month
	exit 10
	end

/* Got a valid month, now see about the year */
select
	when year = "" then nop	/* myyear is already right */
	when ~datatype(year, 'Numeric') then do
		say "Year must be a number between 1 and 9999, not" year
		exit 10
		end
	when length(year) = 2 then myyear = '19'year
	otherwise myyear = year
	end

if myyear < 1 | myyear > 9999 then do
	say "Year must be between 1 and 9999 inclusive, not" myyear
	exit 10
	end

/* Figure out what day of the week that month started on */
firstday = jan1(myyear)

/* Get difference in weekdays between this year & next */
fudge = (jan1(myyear + 1) + 7 - firstday) // 7

select
	/* this is a regular year */
	when fudge = 1 then months.2.days = 28

	/* This is a leap year */
	when fudge = 2 then months.2.days = 29

	/* Otherwise, it must be 1752! */
	otherwise
		months.2.days = 29
		months.9.days = 19
	end

do i = 1 to mymonth - 1
	firstday = firstday + months.i.days
	end

firstday = firstday // 7		/* Got the day of the week */

/*
 * Now, go from that to the name of a day of the week. This table is also
 * used for formatting the output. The line at the top of the body consists
 * of these things concatenated together, with a space in between them.
 * The length of that string is the width of the calendar. Finally, we
 * line the numbers up under the last character of each name. All names
 * _must_ be the same length for this to work.
 */
daynames.0 = 'Sun'
daynames.1 = 'Mon'
daynames.2 = 'Tue'
daynames.3 = 'Wed'
daynames.4 = 'Thu'
daynames.5 = 'Fri'
daynames.6 = 'Sat'

firstday = daynames.firstday		/* and now it's name */

/* Get number of days in this month */
days = months.mymonth.days

/* Next, we set up the header for the calendar. */
headerline = daynames.0
do i = 1 to 6
	headerline = headerline daynames.i
	end
linelength = length(headerline)			/* width of calendar */

/* Set up the header for the calender */
lines.1 = center(months.mymonth myyear, linelength)
lines.2 = " "
lines.3 = headerline
linecount = 4	/* First line of body of calendar */

/* Now set up to put together lines of the body */
maxline = linecount + 5			/* 6 weeks on a monthly calendar, max */
do i = linecount + 1 to maxline
	lines.i = ""
	end

width = length(daynames.0)
outline = right(1, index(headerline, firstday) - 1 + width)
linelength = linelength - width

/*
 * Special case the first & second of the month to deal with September, 1752.
 */
if length(outline) <= linelength then outline = outline right(2, width)
else do
	lines.linecount = outline
	linecount = linecount + 1
	outline = right(2, width)
	end

if days > 20 then start = 3
else do
	days = days + 11
	start = 14
	end

do i = start to days
	if length(outline) <= linelength then
		outline = outline right(i, width)
	else do
		lines.linecount = outline
		linecount = linecount + 1
		outline = right(i, width)
		end
	end
lines.linecount = outline

/* now display it - in a window if possible, to the console if not */
if ~show('Libraries', 'rexxarplib.library') then do
	if ~addlib('rexxarplib.library', 0, -30) then do
		/* Now rexxarplib, just dump it to the console */
		do i = 1 to linecount
			say lines.i
			end
		exit
		end
	end

/* Got a rexxarplib, so put it in a window */
outline = lines.1
do i = 2 to maxline
	outline = outline '\'lines.i
	end

/*
 * We tack a space onto the end here, and in each line, so they will be
 * cleared by postmsg. Sigh.
 */
call postmsg 395, 11, outline ""
exit

/*
 * jan1 - returns the day of the week that january first falls on for
 *	any specific year, 1 through 9999 (assuming they don't change
 *	the rules again).
 */
jan1: procedure
	arg year

	/* Julian calendar; one extra day every four years */
	day = 4 + year + (year + 3) % 4

	/* Gregorian calendar - lose three days over four centuries */
	if year > 1800 then do
		day = day - (year - 1701) % 100
		day = day + (year - 1601) % 400
		end

	/* And the instant changeover in 1752 */
	if year > 1752 then
		day = day + 3

	return day // 7
SHAR_EOF
cat << \SHAR_EOF > post.rexx
/* post - puts it's standard input in the postmsg window */

if ~show('Libraries', 'rexxarplib.library') then do
	if ~addlib('rexxarplib.library', 0, -30) then do
		say "No rexxarplib, so no posting!"
		exit
		end
	end

if arg() = 0 then 'execio stem lines.'
else 'execio read' arg(1) 'stem lines.'

if lines.0 > 0 then do
	out = translate(lines.1, " ", '09'x)
	do i = 2 to lines.0
		out = out '\' || translate(lines.i, " ", '09'x)
		end
	end

call postmsg , , out ""
exit
SHAR_EOF
cat << \SHAR_EOF > nomsg.rexx
/* nomsg - turn of thepostmsg window */
if ~show('Libraries', 'rexxarplib.library') then do
	if ~addlib('rexxarplib.library', 0, -30) then do
		say "A msg window and no rexxarplib? Good trick, that."
		exit
		end
	end

call postmsg
exit
SHAR_EOF
cat << \SHAR_EOF > expand.rexx
/* expand - function to expand AMIGAdos wild cards */
parse arg	files


out = ""
do i = 1 to words(files)
	pat = word(files, i)
	if verify(pat, '#?', 'Match') = 0 then
		out = out pat
	else do
		'list nohead quick'  pat '| execio stem lines.'
		do i = 1 to lines.0
			out = out lines.i
			end
		end
	end
dropbuf		/* just to be sure */
return out

break_c:
	dropbuf
	return ""
SHAR_EOF
cat << \SHAR_EOF > foreach.rexx
/*
 * foreach - execute commands from stdin for each file in arg list,
 *	replacing any "%"'s with the file's name.
 */
parse arg arg

'execio stem commands.'		/* Get commands into the command buffer */

files = expand(arg(1))

do i = 1 to words(files)
	file = word(files, i)
	do j = 1 to commands.0
		command = mapinfile(commands.j, file)
		command
		end
	end
exit

/*
 * mapinfile - replace every occurence of % in the first argument with the
 *	second argument.
 */
mapinfile: procedure
parse arg pattern, fill

	i = index(pattern, '%')
	do while i > 0
		pattern = substr(pattern, 1, i - 1) || fill || substr(pattern, i + 1)
		i = index(pattern, '%')
		end
	return pattern
SHAR_EOF
cat << \SHAR_EOF > man.rexx
/* man - just get me a man page */
arg	page

file = 'docs:'page
if exists(file) then 'more' file
exit
SHAR_EOF
#	End of shell archive
exit 0
--
It's been a hard day's night,				Mike Meyer
And I been working like a dog.				mwm@berkeley.edu
It's been a hard day's night,				ucbvax!mwm
I should be sleeping like a log.			mwm@ucbjade.BITNET