[comp.sys.atari.8bit] LittleLister Action! source

curzon@kaoa01.dec.com (Richard Curzon KAO4-3/7A DTN 621-2196) (11/10/87)

  For those interested in the Action! language, this is the LittleLister
source code. In order to represent the non-ASCII characters, it was
prepared by LittleLister itself.  It prefixes the inverse video
characters with a "@" -- so it will need some editing to run... 

  If you are checking out compiled languages for the 8bit, you will note
Action! has similarities to Pascal and C, as can be seen in this
example.  And it is faster in compilation, and compactness of code
produced than any other hi-level language on the 8 bit.  A pleasure
to use, comes with a good built-in program editor.

  Potentially interesting things:

procedure GetAD(), PutAD() - block I/O suggested by Bruce
             Langdon
procedure Get_Wds() -  gets the words from the command line for
             Sparta DOS, DOS XL as well as detecting whether
             the DOS in use has command line capability
procedure End() -  goes to DOS (not too tricky), but
             this procedure also keeps the stack clear, regardless
             of how deeply nested you are when you call it.
procedure Clr_Dos()  - a work around.  I found that if I returned to 
             SpartaDOS, when the last disk access was for write or
             update, I often got some out-of-control disk writing.  
             This function ensures that the last disk access was a 
             read before we exit to DOS.  [If anybody can explain, I
             would like to know what causes this!]
---------------------------------------------

;LL.ACT OCT 15,1987 -  R CURZON
;(I/O from PRINT.ACT by Bruce Langdon)
 
;locate above the G: device by
;CF Johnson, to allow graphics
;output
SET 14=$2F01
SET $491=$2F01
 
; command line dos will try to run
;  twice unless we put rts at start
 
BYTE rts = [$60]
 
; --System Variables
 
BYTE shflok = $2BE, ch = $2FC,
     crsinh = $2F0
CARD sdslst = $230
 
; --Working globals
 
; First global ARRAY, other than
; BYTE ARRAY of length < 257,
; is placed AFTER rest of program
 
BYTE ARRAY in_b(257) ; locate
                     ; the in_buff
; variables array
 
BYTE ARRAY vars
BYTE pr_wid = [80], file_lim = [39],
 col_lim = [2], file_marg = [2],
 line_lim = [56], page_len = [66],
 top_bl = [5], bott_bl = [5],
 pause_fl = ['Y], convert_fl = ['S],
 page_st = [1]
 
;  PRECEDING SHOULD BE CHANGED ONLY
;  WITH CARE IN ORDER FOR "S" COMMAND
;  TO UPDATE LL.COM TO WORK
 
BYTE ARRAY convert_st = "        "
 
BYTE c_wds ;command line flag
 
BYTE r_ent =[0]  ;flags if program
           ;entered through Run_Ent
 
BYTE file_l, col_l, line_l
 
BYTE ARRAY out_b
CHAR ARRAY out_dev(20),
      in_fil(20)
 
CARD line_c, file_c, col_c, out_s,
      in_s, in_c, out_i, in_i
 
BYTE op_ok, b, page_n, b_wid,
     col_wid
 
BYTE cio_status ; global for CIO
; return value (per ACS convention)
 
INCLUDE "RTIME.ACT"
 
PROC End=*()
  [$68$AA$68$CD$2E8
  $90$5$CD$2E6$90$F3
  $48$8A$48$60]
; entry: PLA; TAX; PLA; CMP MEMLO+1;
; BCC lab; CMP MEMTOP+1; BCC entry;
; lab: PHA; TXA; PHA; RTS
;
; Trace back thru RTS's and
; return to cartridge or DOS.
; From ACS bulletin board.
 
 
; error routines
 
PROC Sys_Error(BYTE errno)
 
PROC Clr_Dos(BYTE chan)
; seems to clear Spartados
; settings for exit to DOS
; (dummy directory)
  Close(chan)
  Open(chan,"D:*.*",6,0)
  Close(chan)
RETURN
 
PROC My_Error(BYTE errno)
  Close(2) Close(3)
  PrintF("error %I. Rerun%E",errno)
  End()
 
PROC D_Error(BYTE errno)
  BYTE i
  IF errno=128 THEN
    Close(2) Clr_Dos(3) End() FI
  PrintF("error %I. Try again%E",errno)
  op_ok = 0
RETURN
 
CARD FUNC GetAD(BYTE chan CARD addr,
 len) ; Block read
  TYPE IOCB = [BYTE hid,dno,com,sta
               CARD badr,put,blen
               BYTE aux1,aux2,aux3,
                  aux4,aux5,aux6]
  IOCB POINTER ic
  BYTE chan16
  chan16 = (chan&$07) LSH 4
  ic = $340+chan16
  ic.com = 7 ; read
  ic.blen = len
  ic.badr = addr
  [$AE chan16 $20 $E456 $8C cio_status]
 
  ; LDX chan JSR CIO STY cio_status
 
  IF cio_status = $88 THEN
    eof(chan) = 1
  FI
RETURN (ic.blen)
 
CARD FUNC PutAD(BYTE chan CARD addr,
  len) ; Block write
  TYPE IOCB = [BYTE hid,dno,com,sta
               CARD badr,put,blen
               BYTE aux1,aux2,aux3,
                  aux4,aux5,aux6]
  IOCB POINTER ic
  BYTE chan16
  chan16 = (chan&$07) LSH 4
  ic = $340+chan16
  ic.com = 11 ; write
  ic.blen = len
  ic.badr = addr
 
  [$AE chan16 $20 $E456 $8C cio_status]
 
  ; LDX chan JSR CIO STY cio_status
 
RETURN(ic.sta)
 
PROC Fix_FlSp(BYTE ARRAY filespec)
  CARD i
  IF filespec(2) <> ': AND filespec(3)
   <> ': THEN
 
 ; if no device, prefix "D:" to file
 
    filespec^ == +2
    i=filespec^
    WHILE i>2 DO
      filespec(i) = filespec(i-2)
      i == -1
    OD
    filespec(1) ='D  filespec(2) =':
  FI
RETURN
 
PROC Show_Hdr()
  Print(
"      @L@i@t@t@l@e@L@i@s@t@e@r@ @2 - R Curzon
'LL' =setup @ @   'RUN 4A60' =rerun
'LL [input [output]]' =command line
")
RETURN
 
PROC Show_Vars()
  PutE()
  PrintF("@A Printer width    : %U%E",
   pr_wid)
  PrintF("@B Width per column : %U%E",
   file_lim)
  PrintF("@C Number of columns: %U%E",
   col_lim)
  PrintF("@D Between columns  : %U%E",
   file_marg)
  PrintF("@E Text lines/page  : %U%E",
   line_lim)
  PrintF("@F Total lines/page : %U%E",
   page_len)
  PrintF("@G Filler lines/top : %U%E",
   top_bl)
  PrintF("@H Filler lines/bot : %U%E",
   bott_bl)
  PrintF("@I Page pause   Y/N : %C%E",
   pause_fl)
  PrintF("@J ASCII/ATASCII/HEX: %S%E",
   convert_st)
  PrintF("@K Starting page num: %U%E",
   page_st)
  PrintF("@L Output device    : %S%E",
   out_dev)
  PutE()
  PrintE("@S Save configuration - @A-@J")
  PrintE("@X Execute")
RETURN
 
PROC Set_Defs()
  BYTE i
  FOR i = 1 TO 20 DO
    in_fil(i) = '
  OD
  in_fil(0) = 0
  page_n = 0
  out_dev(0)=2
  out_dev(1)='P
  out_dev(2)=':
  vars = @pr_wid
RETURN
 
PROC Set_Vars()
  BYTE change, i, j, save_fail
  BYTE loc_err
  ch = 255
  Close(4)
  Open(4,"K:",4,0)
  loc_err = 0
  save_fail = 0
  DO ; check for bad values, allow
     ; changes to program variables
    IF col_lim = 0 THEN col_lim =1 FI
    IF line_lim=0 THEN line_lim =1 FI
    IF convert_fl ='S THEN
       convert_st = "ASCII   "
    ELSEIF convert_fl ='T THEN
       convert_st = "ATASCII"
    ELSE convert_st = "HEX    "
    FI
    crsinh = 1
    Put(125)
    Show_Hdr()
    Show_Vars()
    Position(5,21)
    IF pr_wid< file_lim * col_lim
      +file_marg * (col_lim-1) THEN
      loc_err = 1
      Print("@I@N@V@A@L@I@D@ @A@,@ @B@,@ @C@,@ @D")
    ELSEIF page_len # line_lim +
      top_bl + bott_bl THEN
      loc_err = 1
      Print("@I@N@V@A@L@I@D@ @E@,@ @F@,@ @G@,@ @H")
    ELSEIF out_dev(1) >= 'a THEN
      loc_err = 1 ;should be upperc.
      Print("@I@N@V@A@L@I@D@ @L")
    ELSEIF save_fail = 1 THEN
      Print("@N@O@ @F@I@L@E@ @D@:@L@L@.@C@O@M")
      save_fail = 0
      loc_err = 0 ; not fatal error
    ELSEIF change = 'S THEN
      Print("LL.COM revised")
      loc_err = 0 ; not error
    ELSE loc_err = 0
    FI
    shflok = $40 ; upper case
    change = GetD(4)
    Position(0,21)
    Print("                       ")
    crsinh = 0
    IF change>= 'a THEN
      change == -32 FI
    IF change>='A and change<='L THEN
      Position(23,change-61)
      Print("             ")
      Position(21,change-61)
      Print(": ")
      IF change<'I OR change ='K THEN
        vars(change - 65) = InputB()
      ELSEIF change = 'I THEN
        IF pause_fl = 'N
          THEN pause_fl = 'Y
        ELSE pause_fl = 'N
        FI
      ELSEIF change = 'J THEN
        IF convert_fl = 'S
          THEN convert_fl = 'T
        ELSEIF convert_fl = 'T
          THEN convert_fl = 'H
        ELSE convert_fl = 'S
        FI
      ELSEIF change = 'L THEN
        InputMD(0,out_dev,20)
        Fix_FlSp(out_dev)
      FI
    FI
    IF change='S AND loc_err= 0 THEN
      Close(3)
      Error = D_Error op_ok = 1
      Open(3,"D:LL.COM",12,0)
      Error = My_Error
      IF op_ok = 1 THEN
        FOR i = 1 TO 13 DO
          j = GetD(3)
        OD       ; find the 14th byte
        FOR i = 0 TO 9 DO
          PutD(3,vars(i))
        OD     ; update the variables
      ELSE save_fail = 1
      FI
      Clr_Dos(3)
    FI
  UNTIL loc_err= 0 AND change= 'X OD
  Close(4)
RETURN
 
PROC Alloc_Buffs()
  CARD size
 
  col_wid = file_lim + file_marg
  b_wid = col_wid *(col_lim)
    -file_marg + 1
 
; set index values
 
  file_l = file_lim -1
  col_l = col_lim -1
  line_l = line_lim -1
 
  ch = 255
 
   ; find size and location of
   ; the output buffer
 
  out_s = (line_lim) * b_wid
  out_b = sdslst - out_s
 
   ; input buffer starting point
   ; was set to end of program
   ; in variable declarations
 
  IF in_b > out_b - 200 THEN
    PrintE(
"@n@o@t@ @e@n@o@u@g@h@ @m@e@m@o@r@y@!@!")
    End() FI
 
   ; find size of input buffer
 
  in_s = sdslst - out_s - in_b
RETURN
 
PROC Print_Clear()
  CARD i, b_ptr, o_b_ptr
  BYTE j, k, n, tc, bc, test
  b_ptr = 0  o_b_ptr = 0
  FOR i = 0 to line_l DO
 
   ; trim trailng spaces from
   ; each print line
 
    n = 0
    FOR j = 0 to b_wid - 1 DO
      IF out_b(b_ptr + j) # '  THEN
        n = j FI
    OD
 
   ; line will be chopped at "n"
 
    b_ptr == + n + 1
    out_b(b_ptr) = $9B
    b_ptr == +1
 
   ; slide everything else down
   ; over the unused space
 
    MoveBlock(out_b + b_ptr,
      out_b + o_b_ptr + b_wid,
      (line_l - i) * b_wid)
    o_b_ptr = b_ptr
  OD
  tc = top_bl   bc = bott_bl
  WHILE tc > 0 DO
    IF top_bl >3 AND tc= top_bl-2
    THEN
 
   ; if enough room print page header
 
      PrintD(3,in_fil)
      FOR i= 9 TO pr_wid-in_fil(0) DO
        PutD(3,' )
      OD
      PrintD(3,"Page ")
      PrintBDE(3,page_n)
      tc == -1
    ELSE
      PutDE(3)  tc == -1
    FI
  OD
  PutAD(3,out_b,b_ptr)
  WHILE bc > 0 DO ;bottom fill lines
    PutDE(3)  bc == -1
  OD
  IF pause_fl= 'Y AND
    out_dev(1) # 'D THEN
    PutE()
    PrintE("@R@E@T@U@R@N@ @=@m@o@r@e@ @,@B@R@E@A@K@ @=@q@u@i@t")
    Close(4)
    Open(4,"K:",4,0)
    ch = 255
    DO test = GetD(4)
    UNTIL test = $9B OD
    Close(4)
  FI
RETURN
 
PROC Rst_Outb()
  file_c = 0  line_c = 0  col_c = 0
  out_i = 0
  SetBlock(out_b,out_s,' )
 
 ; 'blank' is not $00!
 
RETURN
 
PROC Compose(BYTE chx)
 ; find where each character belongs
 ;  in the output buffer
 
  IF chx = $9B OR file_c>file_l THEN
    out_i == -file_c + b_wid
    line_c == +1
    file_c = 0
  FI
  IF chx = $9B THEN RETURN FI
  IF line_c>line_l THEN
    col_c == +1
    out_i = col_c * col_wid
    line_c = 0
    file_c = 0
  FI
  IF col_c>col_l THEN
    page_n == +1
    IF page_n >= page_st THEN
      Print_Clear()
    FI
    Rst_Outb()   ;clear/reset ptrs
  FI
 
 ;
 ; out_i now points to where to put
 ;  this character
 ;
 
  out_b(out_i) = chx
  file_c == +1  out_i == +1
RETURN
 
PROC Op_File()
BYTE dnum
BYTE ARRAY dir_wk(21)
BYTE ARRAY dir_nm = "Dn:*.*"
  ch = 255
  dnum = 0
  op_ok = 1
  DO
    IF in_fil(0) = 0 OR r_ent = 1
      OR op_ok = 0
      THEN
 
; if menu, set position
      IF (c_wds < 2 OR r_ent = 1)
         AND dnum = 0 THEN
        Position(25,21)
        Print("            ")
        Position(2,21)
      FI
      Print("@S@o@u@r@c@e(RET quits/1-4,8):")
      shflok = $40 ; upper case
      dnum = 0
      DO UNTIL ch # 255 OD
      IF ch = 31 THEN dnum = 1 FI
      IF ch = 30 THEN dnum = 2 FI
      IF ch = 26 THEN dnum = 3 FI
      IF ch = 24 THEN dnum = 4 FI
      IF ch = 53 THEN dnum = 8 FI
      IF dnum # 0 THEN
        dir_nm(2) = dnum + '0
        ch = 255
        op_ok = 1
        Error = D_Error
        Close(2)
        Open(2,dir_nm,6,0)
        IF op_ok = 1 THEN
          PrintF("%E%E@D@r@i@v@e@ @#@ %C%E%E",
            dnum + '@0 )
          DO
            InputMD(2,dir_wk,20)
            IF op_ok = 0 THEN EXIT FI
            PrintE(dir_wk)
            IF dir_wk(1) >= '0 AND
              dir_wk(1) <= '9 THEN EXIT
            FI
          OD
          PutE()
        FI
        Close(2) op_ok = 0
        Error = My_Error
      ELSE
        InputS(in_fil)
        IF in_fil^ = 0 THEN
          End() FI
        Fix_FlSp(in_fil)
      FI
    FI
    Error = D_Error
    IF dnum = 0 THEN
      Close(2)
      op_ok = 1
      Open(2,in_fil,4,0)
    FI
  UNTIL op_ok OD
  Error = My_Error
RETURN
 
PROC Hcompose(BYTE chx)
BYTE t
  Compose('$)
 
  t =(chx&$F0) RSH 4 + '0
  IF t > '9 THEN t == +7 FI
  Compose(t) ; first digit
 
  t =(chx&$0F) + '0
  IF t > '9 THEN t == +7 FI
  Compose(t) ; last digit
RETURN
 
PROC Print_File()
  BYTE t
  CARD i
  Rst_Outb()
  Op_File()
  Close(3)
  Open(3,out_dev,8,0)
 
  IF convert_fl = 'T THEN
    DO
      in_c =GetAD(2,in_b,in_s)
      FOR i = 0 TO in_c - 1 DO
        Compose(in_b(i))
      OD
      IF eof(2) THEN
        page_n == +1
        Print_Clear() EXIT
      FI
    UNTIL eof(2) OD
 
  ELSEIF convert_fl = 'H THEN
    DO
      in_c =GetAD(2,in_b,in_s)
      FOR i = 0 TO in_c - 1 DO
        Hcompose(in_b(i))
      OD
      IF eof(2) THEN
        page_n == +1
        Print_Clear() EXIT
      FI
    UNTIL eof(2) OD
 
  ELSEIF convert_fl ='S THEN
 
    DO
      in_c =GetAD(2,in_b,in_s)
      FOR i = 0 TO in_c - 1 DO
        IF in_b(i) =$9B THEN
          Compose($9B)
        ELSE t = in_b(i) & $7F
          IF t >26 AND t <32 OR
            t =96 OR t >122 THEN
            Hcompose(in_b(i))
          ELSE
            IF in_b(i) > $7F THEN
              Compose('@) FI
            IF t < 27 THEN
              Compose('^)
              Compose(t + $40)
            ELSE Compose(t)
            FI
          FI
        FI
      OD
      IF eof(2) THEN
        page_n == +1
        Print_Clear() EXIT
      FI
    UNTIL eof(2) OD
  FI
  Close(2)
  Clr_Dos(3)
RETURN
 
PROC Get_wds()
  CARD POINTER dosvec = $0A
  BYTE POINTER comtab_ptr1
  BYTE POINTER comtab_ptr2
  BYTE ARRAY c_line, wk_d
  BYTE i, j, eol_fl
 
  in_fil(0) = 0
  comtab_ptr1 = dosvec^ + 3
 
  c_wds = 0
; no of words on command line
; 0 means not a comm line type DOS
 
; command line DOS's have a JMP instr
; at comtab + 3 to file crunch
; routine
  IF (comtab_ptr1^) # $4C THEN
    RETURN
  FI
 
; but make sure it's not Machdos
; (no command line)
  comtab_ptr1 = dosvec^ + 6
  comtab_ptr2 = dosvec^ + 9
  IF (comtab_ptr1^) = $4C AND
     (comtab_ptr2^) = $4C THEN
    RETURN
  FI
 
  c_line = dosvec^ + 63
 
; get command line words
  eol_fl = 0
  i = 0
  DO
 
; find start of word
    DO
      IF c_line(i) = $9B OR
        i > 63 THEN
        eol_fl = 1 EXIT
      ELSEIF c_line(i) # '  THEN EXIT
      ELSE i == +1 FI
    OD
    IF eol_fl THEN EXIT FI
 
; trace to end of word, store
    j = 1
    c_wds == +1
 
; ignore 1st word only
    IF c_wds = 2 THEN wk_d = in_fil
    ELSEIF c_wds=3 THEN wk_d=out_dev
    FI
 
    IF c_wds > 1 THEN
      DO
        wk_d(j) = c_line(i)
        i == +1
        IF c_line(i) = $9B OR i > 63
          THEN eol_fl = 1 FI
        IF c_line(i) ='  OR eol_fl =1
          THEN wk_d(0) = j EXIT FI
        j == +1
      OD
      Fix_FlSp(wk_d)
    ELSE
      DO
        i ==+1
        IF c_line(i) = $9B THEN
          eol_fl = 1 EXIT
        ELSEIF c_line(i)='  THEN EXIT
        FI
      OD
    FI
  UNTIL eol_fl = 1 OR c_wds = 3 OD
RETURN
 
PROC Run_Ent()
; entry point for RUN dos command
  r_ent = 1
 
PROC Main()
  device = 0 ; suggested by ACS
  Sys_Error = Error
  Error = My_Error
  Set_Defs()
 
; check if command line type DOS,
;  and if filename on the command
;  line
 
  Get_wds()
  DO
    IF c_wds > 1 AND r_ent = 0 THEN
      Show_Hdr()
    ELSE Set_Vars()
    FI
    Alloc_Buffs()
    Print_File()
    Set_Defs()
    IF c_wds > 1 THEN EXIT FI
  OD
  Close(2)
  IF out_dev(1) = 'D THEN Clr_Dos(3)
    ELSE  Close(3) FI
RETURN