kim@amdahl.uts.amdahl.com (Kim DeVaughn) (04/02/88)
[ "A car is just a big purse on wheels." --Johanna Reynolds ] In a recent posting concerning ARexx and IPC, as an example of ARexx's scripting/macro capabilities, I made reference to an amicron initiated, talking alarm clock program that one of my co-workers whipped off. I hadn't really thought about posting it, until Peter da Silva catagorized the REXX language as being "PL/I like". Bunk. So, in the interest of education, and with Bob Rethemeyer's permission (he's the author), here's "cuckoo", along with a crontab file. Also included is a 336-byte, "bare-bones", assembly language substitute for the "say" command. It's valuable in it's own right as an assembly language example of using the translator.library and narrator.device. [ Coincidentally, I just saw a posting requesting assembly language examples for inclusion into a freely redistributable library, similar in concept to the Fish Disks. Feel free to include "mumble". ] Bear in mind that the REXX language has many more features, and power than are used in "cuckoo". It should, however, give you a "feel" for what the language is like. Note too, that this example makes implicit use of IPC to communicate to AmigaDOS (where it invokes the "say" command [line 19], and also where it invokes whatever is equated to "speak" [lines 8, 59, 60, and 62], which in this case is "mumble"). Hope some of you find this example useful! /kim # This is a shell archive. Remove anything before this line, then # unpack it by saving it in a file and typing "sh file". (Files # unpacked will be owned by you and have default permissions.) # # This archive contains: # cuckoo.rexx timeto.rexx sample.crontab mumble.asm mumble.uue echo x - cuckoo.rexx cat > "cuckoo.rexx" << '//E*O*F cuckoo.rexx//' /* CUCKOO: ANNOUNCES THE CURRENT TIME. R. Rethemeyer 03-88 * * Cuckoo is useful with AmiCron to announce times for events. * * The "MUMBLE" program is used for the voice output. * * If that is not available, change 'speak' to "sys:system/say".* * Usage: "RX CUCKOO [ALARM]" * * The ALARM option produces an obnoxious noise and message. */ /*--------------------------------------------------------------------*/ speak="Mumble" /* PROGRAM FOR VOICE OUTPUT */ nice="Excuse me sir, the time iz now" /* NORMAL MESSAGE */ nasty="All right u bum, get up. Nouw. The time iz" /* ALARM MESSAGE */ dingaling="gggggggggggggggggggggggggggg" /* OBNOXIOUS ALARM NOISE */ /*--------------------------------------------------------------------*/ arg opt if opt="ALARM" then intro=nasty ; else intro=nice zhour = time('h') xmin = time('m') xmin = xmin-((xmin%60)*60) xhour = zhour say "Cuckoo at" zhour||":"||xmin mnite = " " if zhour > 12 then xhour = zhour-12 select when xhour=0 then do; xhour="twelve"; if xmin=0 then mnite="midnite"; end when xhour=11 then xhour = "elaven" when xhour=12 then do; xhour="twelve"; if xmin=0 then mnite="noon"; end otherwise nop end smin=" " if xmin=0 then tmin = "o clock" else do tmin=xmin%10 if tmin=1 then do; select when xmin=10 then tmin = "ten" when xmin=11 then tmin = "elaven" when xmin=12 then tmin = "twelve" when xmin=13 then tmin = "thirt teen" when xmin=14 then tmin = "fourt teen" when xmin=15 then tmin = "fif teen" when xmin=16 then tmin = "six teen" when xmin=17 then tmin = "seven teen" when xmin=18 then tmin = "eight teen" when xmin=19 then tmin = "nine teen" end end else do smin=xmin if xmin>9 then smin=xmin-(tmin*10) if smin=0 then smin=" " select when tmin=0 then tmin = "oh" when tmin=2 then tmin = "twenty" when tmin=3 then tmin = "thirty" when tmin=4 then tmin = "forty" when tmin=5 then tmin = "fifty" end end end if opt="ALARM" then address COMMAND speak dingaling address COMMAND speak intro xhour tmin smin mnite "." if tmin="o clock" & opt="ALARM" then , address COMMAND speak "I repeat," xhour tmin "." exit //E*O*F cuckoo.rexx// echo x - timeto.rexx cat > "timeto.rexx" << '//E*O*F timeto.rexx//' /* speak a sentence prefixed by time */ parse arg sentence cuckoo /* announce the time first */ address command "mumble Its time to " sentence "." exit //E*O*F timeto.rexx// echo x - sample.crontab cat > "sample.crontab" << '//E*O*F sample.crontab//' 0,15,30,45 * * * * rx cuckoo 0,10,20,30,40,50 7 * * 1-5 rx cuckoo alarm 30 7,18 * * * rx timeto feed the cat //E*O*F sample.crontab// echo x - mumble.asm cat > "mumble.asm" << '//E*O*F mumble.asm//' PLEN 60 ********************************************************************** * Program: MUMBLE - bare-bones CLI substitute for SAY command * * Author: Robert Rethemeyer, Sunnyvale, CA (@BBS-HT or BBS-JC) * * Revision: 0.1 03/30/88 initial release * * Status: RELEASED TO THE PUBLIC DOMAIN, "AS-IS" * ********************************************************************** * MUMBLE is a very small CLI program which speaks the text on the * * command line using the Amiga's translator/narrator voice output. * * It is convenient for use in CLI or ARexx scripts. * * Command usage: MUMBLE <text> * ********************************************************************** * MUMBLE provides a function similar to the command line usage of * * the SAY command, but takes much less memory and disk space * * (300 bytes vs. 9K+). It is not, however, as versatile as SAY. * * There are no -options; the voice parameters are fixed, and the * * program will not run in window mode or read from a file. * ********************************************************************** * Mumble return codes: * 0= success * 1-9,20-26= narrator IO error * 11= could not allocate memory * 12= could not open translator.library * 13= could not open narrator.device ********************************************************************** NOLIST INCLUDE "exec/types.i" INCLUDE "exec/io.i" INCLUDE "exec/ports.i" INCLUDE "exec/memory.i" INCLUDE "devices/narrator.i" LIST XREF _LVOOpenLibrary XREF _LVOCloseLibrary XREF _LVOAllocMem XREF _LVOFreeMem XREF _LVOOpenDevice XREF _LVOCloseDevice XREF _LVOTranslate XREF _LVOFindTask XREF _LVOAddPort XREF _LVORemPort XREF _LVODoIO ExecBase EQU 4 execptr EQUR A6 ********************************************************************** * Voice parameters can be changed here, to user's liking: VSEX EQU MALE MALE/FEMALE/DEFSEX VMODE EQU NATURALF0 NATURALF0/ROBOTICF0/DEFMODE VRATE EQU 180 40-400/DEFRATE VFREQ EQU DEFFREQ 5000-28000/DEFFREQ VPITCH EQU DEFPITCH 65-320/DEFPITCH VVOL EQU DEFVOL 0-64/DEFVOL ********************************************************************** Mumble: MOVEQ #0,d5 return code if parmlen=0 MOVE.L d0,d4 SAVE EXECUTION PARMS parmlen BEQ endprog do nothing if parmlen=0 MOVE.L a0,d3 save parmaddr MOVE.L ExecBase,execptr a6=exec lib pointer * ALLOCATE SCRATCH MEMOR% MOVEQ #11,d5 return code if this fails ASL.L #2,d0 size of TRarea = parmlen*4 ADD.L #scratchlen,d0 add to size of scratch area MOVE.L d0,d6 remember for deallocate later MOVE.L #MEMF_PUBLIC+MEMF_CLEAR,d1 mem flags JSR _LVOAllocMem(execptr) ask for the storage MOVE.L d0,a3 a3=scratch area ptr BEQ broke1 abort if request failed * OPEN TRANSLATOR LIBRARY MOVEQ #12,d5 return code if this fails LEA tranlib(pc),a1 addr of library name MOVEQ #0,d0 any version will do JSR _LVOOpenLibrary(execptr) get library pointer MOVE.L d0,a5 a5=tran lib pointer BEQ broke2 back out if no lib * TRANSLATE COMMAND LINE PARAMETER MOVE.L d3,a0 retrieve parmaddr MOVE.L d4,d0 and parmlen LEA TRarea(a3),a1 point to xlat out buff ASL.L #2,d4 figure out buff length again MOVE.L d4,d1 for func (and save for later) JSR _LVOTranslate(a5) translate to phonemes MOVE.L a5,a1 : JSR _LVOCloseLibrary(execptr) close trans lib * INIT NARRATOR DEVICE PORT MOVE.L #0,a1 : JSR _LVOFindTask(execptr) identify this task MOVE.L d0,Narport+MP_SIGTASK(a3) let narrator find it LEA Narport(a3),a1 point to the port area JSR _LVOAddPort(execptr) install narrator port * INIT NARRATOR DEVICE MOVEQ #13,d5 return code if this fails LEA Narname(pc),a0 point to device name MOVEQ #0,d0 unit 0 LEA Nardev(a3),a1 point to device structure MOVEQ #0,d1 no flags JSR _LVOOpenDevice(execptr) open narrator device TST.L d0 if device open failed BNE.S broke3 then back out * INIT DEVICE STUFF LEA Nardev(a3),a1 a1=device structure LEA Narport(a3),a0 a0=port address MOVE.L a0,MN_REPLYPORT(a1) give port addr to device LEA audmaps(pc),a0 audio maps MOVE.L a0,NDI_CHMASKS(a1) addr of maps MOVE.W #4,NDI_NUMMASKS(a1) number of masks MOVE.W #VPITCH,NDI_PITCH(a1) init pitch MOVE.W #VRATE,NDI_RATE(a1) init rate MOVE.W #VVOL,NDI_VOLUME(a1) init volume MOVE.W #VFREQ,NDI_SAMPFREQ(a1) init sample freq MOVE.W #VSEX,NDI_SEX(a1) init sex MOVE.W #VMODE,NDI_MODE(a1) init mode MOVE.W #CMD_WRITE,IO_COMMAND(a1) init device command MOVE.L d4,IO_LENGTH(a1) length of buffer LEA TRarea(a3),a0 addr of buffer MOVE.L a0,IO_DATA(a1) : * THE MOMENT OF TRUTH JSR _LVODoIO(execptr) do i/o, wait for reply MOVE.L d0,d5 save return code NEG.L d5 convert rc to positive * CLEAN UP AND RETURN LEA Nardev(a3),a1 point to device structure JSR _LVOCloseDevice(execptr) release device broke3 LEA Narport(a3),a1 point to port JSR _LVORemPort(execptr) delete the port broke2 MOVE.L d6,d0 length of scratch area MOVE.L a3,a1 addr of scratch area JSR _LVOFreeMem(execptr) free scratch mem broke1 MOVE.L d5,d0 set return code endprog RTS ALL DONE! ************************************************************ CNOP 0,2 tranlib DC.B 'translator.library',0 CNOP 0,2 narname DC.B 'narrator.device',0 CNOP 0,2 audmaps DC.B 3,5,10,12 Audio device maps ************************************************************* version DC.B 'MUMBLE V0.1 RAR' Imbedded version info ************************************************************* STRUCTURE Scratch,0 Format of allocated scratch mem STRUCT Narport,MP_SIZE Message reply port for narrator STRUCT Nardev,NDI_SIZE Narrator IO block LABEL scratchlen Length of scratch area less TRarea STRUCT TRarea,0 xlat out buff (size computed dynamically) END and there ain't no more //E*O*F mumble.asm// echo x - mumble.uue cat > "mumble.uue" << '//E*O*F mumble.uue//' begin 755 mumble M```#\P`````````!``````````````!+```#Z0```$MZ`"@`9P``ZB8(+'@`^ M!'H+Y8`&@````&@L`"(\``$``4ZN_SHF0&<``,9Z#$/Z`,1P`$ZN_=@J0&<`) M`*P@0R`$0^L`:.6$(@1.K?_B(DU.KOYB(GP`````3J[^VB=``!!#ZP``3J[^0 MGGH-0?H`FG``0^L`(G(`3J[^1$J`9F!#ZP`B0>L``"-(``Y!^@"*(T@`.#-\& M``0`/#-\`&X`,C-\`+0`,#-\`$``/C-\5K@`0#-\````-C-\````-#-\``,`& M'"-$`"1!ZP!H(T@`*$ZN_C@J`$2%0^L`(DZN_CY#ZP``3J[^F"`&(DM.KO\NW M(`5.=71R86YS;&%T;W(N;&EB<F%R>0``;F%R<F%T;W(N9&5V:6-E``,%"@Q-' 554U"3$4@5C`N,2!205(```````/RT `` end size 336 //E*O*F mumble.uue// echo Possible errors detected by \'wc\' [hopefully none]: temp=/tmp/shar$$ trap "rm -f $temp; exit" 0 1 2 3 15 cat > $temp <<\!!! 63 331 2294 cuckoo.rexx 5 28 152 timeto.rexx 3 25 109 sample.crontab 147 730 8084 mumble.asm 13 15 506 mumble.uue 231 1129 11145 total !!! wc cuckoo.rexx timeto.rexx sample.crontab mumble.asm mumble.uue | sed 's=[^ ]*/==' | diff -b $temp - exit 0 -- UUCP: kim@amdahl.amdahl.com or: {sun,decwrl,hplabs,pyramid,ihnp4,uunet,oliveb,cbosgd,ames}!amdahl!kim DDD: 408-746-8462 USPS: Amdahl Corp. M/S 249, 1250 E. Arques Av, Sunnyvale, CA 94086 CIS: 76535,25
kim@amdahl.uts.amdahl.com (Kim DeVaughn) (04/05/88)
In article <26223@amdahl.uts.amdahl.com>, I wrote: > > Note too, that this example makes implicit use of IPC > to communicate to AmigaDOS (where it invokes the "say" command [line 19], > and also where it invokes whatever is equated to "speak" [lines 8, 59, 60, > and 62], which in this case is "mumble"). Ooooops! The "say" command on line 19 refers to the *internal* ARexx command "say" ... roughly the REXX equivalent to "printf()". Sorry for any confusion this may have caused ... /kim -- UUCP: kim@amdahl.amdahl.com or: {sun,decwrl,hplabs,pyramid,ihnp4,uunet,oliveb,cbosgd,ames}!amdahl!kim DDD: 408-746-8462 USPS: Amdahl Corp. M/S 249, 1250 E. Arques Av, Sunnyvale, CA 94086 CIS: 76535,25
peter@nuchat.UUCP (Peter da Silva) (04/07/88)
In article ... kim@amdahl.uts.amdahl.com (Kim DeVaughn) writes: > I hadn't really thought about posting it, until Peter da Silva catagorized > the REXX language as being "PL/I like". Bunk. It's PL/1-like. I've extensive experience with another PL/1 derivitive (namely PL/M), and moderate experience with PL/1 itself (despite my best attempts at avoiding it :->). There's nothing inherently wrong with being PL/1-like, so don't be so defensive. I just happen to prefer weird C derivitives. > say "Cuckoo at" zhour||":"||xmin ^ Don't you want a concatenation operator here? > select > when xhour=0 then do; xhour="twelve"; if xmin=0 then mnite="midnite"; end > when xhour=11 then xhour = "elaven" > when xhour=12 then do; xhour="twelve"; if xmin=0 then mnite="noon"; end > otherwise nop > end An improvement over "DO CASE", I must say. > else do > tmin=xmin%10 > if tmin=1 then do; ^ Isn't this redundant? > if opt="ALARM" then address COMMAND speak dingaling ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Mind explaining this construct? -- -- a clone of Peter (have you hugged your wolf today) da Silva `-_-' -- normally ...!hoptoad!academ!uhnix1!sugar!peter U -- Disclaimer: These aren't mere opinions... these are *values*.
kim@amdahl.uts.amdahl.com (Kim DeVaughn) (04/10/88)
In article <896@nuchat.UUCP>, peter@nuchat.UUCP (Peter da Silva) writes: > In article ... kim@amdahl.uts.amdahl.com (Kim DeVaughn) writes: > > I hadn't really thought about posting it, until Peter da Silva catagorized > > the REXX language as being "PL/I like". Bunk. > > It's PL/1-like. I've extensive experience with another PL/1 derivitive > (namely PL/M), and moderate experience with PL/1 itself (despite my best > attempts at avoiding it :->). Fine. *I* find it to be closer in flavor to elementary C code, than to PL/I. It's really quite different than either, so this discussion is pretty pointless (and therefore, I won't comment on it further in future postings). I will say that (as with any language), there are a number of things I *don't* like about the REXX language. I'll put up with them though because of all of the flexibility and capability the ARexx *package* gives me. > There's nothing inherently wrong with being PL/1-like, so don't be so > defensive. I just happen to prefer weird C derivitives. Not defensive. I personally find PL/I to be a disgusting language, that I've had to deal with alot more than I would have cared to. BTW, I assume we're talking about the same language ... PL/I. I've never used anything called PL/1 ... :-) > > say "Cuckoo at" zhour||":"||xmin > ^ Don't you want a concatenation operator here? No. The space is a concatation operator, which (logically enough) gives you: the LHS of the expression, a space, and the RHS of the expression. REXX, you see, is a language oriented toward text processing, and has several features that facilitate this. It this instance, you really aren't aware that an operator is being used, unless you think about it. Another point ... the explicit || concatenation operators aren't really needed here at all. Bob just used them for clarity. REXX is flexible enough that there are often several ways to specify the same action. There *are* cases where the || operator is needed, BTW. > > else do > > tmin=xmin%10 > > if tmin=1 then do; > ^ Isn't this redundant? Yeah. Doesn't hurt anything though. Sorta like C lets you code: if (foo) {x++;} where the braces are redundant. > > if opt="ALARM" then address COMMAND speak dingaling > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Mind explaining this > construct? Glad you asked. You are looking at one of the reasons why ARexx and the REXX language is so well suited to serve as a script/macro/IPC processing hub. REXX uses the concept of an "address" to determine who should process a given command. The above form is a very explicit way of telling the interpreter that this command is for the OS (that's what "command" specifies ... the OS). In this example, what gets passed to AmigaDOS for execution is: "Mumble ggggggggggggggggggg" due to the assignments made for "speak" and "dingaling" (mumble is the stripped- down, assembly language version of the AmigaDOS "say" command that was posted along with this example). This is important to note: the commands that are to be passed to an external program (OS, or whatever), can be coded as REXX *expressions*, and not merely specified as a hard-coded string. Flexible. And powerful. Had this been *my* code, I might well have just put the REXX statement "address command" up at the top of the REXX program, and then I could have just written: if opt="ALARM" then speak dingaling and it would've worked in the same way. I.e., the REXX interpreter dosn't understand "Mumble" as a command, it sees that the "address" has been set to "command", and so passes it on to the OS, assuming that it (the OS) will know what to do with it. If the OS *doesn't* know, you get an error back (command not found, etc). Of course the "address" specified could have been any application set up to talk to ARexx, so you could say "address TXED", or "address DME", etc. and passed commands to those applications just as easily. Also, if the REXX program had been invoked *from* such a host (i.e., as a macro), there is no need to use the "address" command at all to issue commands back to that host, as the interpreter keeps track of who the invoking program was. Anything it (the interpreter) doesn't understand gets passed back to the invoking host by default. Or you can change where it goes. Start to see how (from the user's point of view) multiple applications can *communicate* (and not just pass data)? There are a number of other nuances that the "address" statement has, one of which is to allow the address itself to be specified by an expression, and not hard-coded. Another is a "toggle" form, that swaps between the current and previous addresses. Etc. I really suggest you take a look at Cowlishaw's book that defines the REXX language: "The REXX Language" "A Practical Approach to Programming" M. F. Cowlishaw Prentice-Hall, 1985 Should be able to find it in your local university library, or a decent computer book store. Or, better yet, get a copy of ARexx from Bill Hawes, and *find out* what it can and cannot do! Then you might be in a position to offer comments that have some substance to them, and not just your own personal opinions, most of which seem to be based on mere conjecture. BTW, for those of you also running MS-DOS on the Bridge, or a PClone, a REXX interpreter is also available for that system from Mansfield Software. Of course it doesn't have quite the capabilities that ARexx provides, since it's not running on a multi-tasking, message-passing system. If interested, email me, and I'll hunt up their address. /kim -- UUCP: kim@amdahl.amdahl.com or: {sun,decwrl,hplabs,pyramid,ihnp4,uunet,oliveb,cbosgd,ames}!amdahl!kim DDD: 408-746-8462 USPS: Amdahl Corp. M/S 249, 1250 E. Arques Av, Sunnyvale, CA 94086 CIS: 76535,25