• ascii-xfr: an example of literate programming

    From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Apr 11 17:11:06 2024
    From Newsgroup: comp.lang.forth

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.
    (Also I need this program, where the it was not attached to minicom.)

    The man page act as a specification.
    \--------------------- 8< ------------------------------------
    \ $Id: ascii-xfr.frt,v 1.6 2024/04/11 14:53:53 albert Exp albert $
    \ Copyright (2024): Albert van der Horst {by GNU Public License}
    \ Literate programming.

    WANT :R TRUE 2VARIABLE BOUNDS $-PREFIX
    \

    \ ASCII-XFR(1) Linux Users Manual ASCII-XFR(1)
    \
    \ NAME
    \ ascii-xfr - upload/download files using the ASCII protocol
    \
    \ SYNOPSIS
    \ ascii-xfr -s|-r [-ednv] [-l linedelay] [-c characterdelay] filename
    \
    \ DESCRIPTION
    \ Ascii-xfr Transfers files in ASCII mode. This means no flow control, no
    \ checksumming and no file-name negotiation. It should only be used if
    \ the remote system doesn't understand anything else.
    \
    \ The ASCII protocol transfers files line-by-line. The EOL (End-Of-Line)
    \ character is transmitted as CRLF. When receiving, the CR character is
    \ stripped from the incoming file. The Control-Z (ASCII 26) character
    \ signals End-Of-File, if option -e is specified (unless you change it to
    \ Control-D (ASCII 4) with -d).
    \
    \ Ascii-xfr reads from stdin when receiving, and sends data on stdout
    \ when sending. Some form of input or output redirection to the modem de-
    \ vice is thus needed when downloading or uploading, respectively.
    \
    \ OPTIONS
    \ -s Send a file.
    VARIABLE action 0 action !
    :F send-file ;
    : -s SHIFT-ARGS 'send-file action ! ;
    \
    \ -r Receive a file. One of -s or -r must be present.
    :F receive-file ;
    : -r SHIFT-ARGS 'receive-file action ! ;

    \ -e Send the End-Of-File character (Control-Z, ASCII 26 by default)
    \ when uploading has finished.
    VARIABLE EOF 0 EOF !
    : -e SHIFT-ARGS ^Z EOF ! ;
    \
    \ -d Use the Control-D (ASCII 4) as End-Of-File character.
    : -d SHIFT-ARGS ^D EOF ! ;
    : send-eof EOF C@ DUP IF EMIT ELSE DROP THEN ;
    \
    \ -n Do not translate CR to CRLF and vice versa.
    VARIABLE do-not-translate FALSE do-not-translate !
    : -n SHIFT-ARGS TRUE do-not-translate ! ;

    \
    \ -v Verbose: show transfer statistics on the stderr output. VARIABLE verbose FALSE verbose !
    : -v SHIFT-ARGS TRUE verbose ! ;

    \
    \ -l milliseconds
    \ When transmitting, pause for this delay after each line. VARIABLE line-delay 0 line-delay ! \ in milliseconds
    : -l SHIFT-ARGS 1 ARG[] EVALUATE line-delay ! SHIFT-ARGS ;
    \
    \ -c milliseconds
    \ When transmitting, pause for this delay after each character.
    \
    VARIABLE char-delay 0 char-delay ! \ in milliseconds
    : -c SHIFT-ARGS 1 ARG[] EVALUATE char-delay ! SHIFT-ARGS ;
    \
    \ file Name of the file to send or receive. When receiving, any exist-
    \ ing file by this name will be truncated.
    \
    \ USAGE WITH MINICOM
    \ If you want to call this program from minicom(1), start minicom and go
    \ to the Options menu. Select File transfer protocols. Add the following
    \ lines, for example as protocols I and J.
    \
    \ I Ascii /usr/bin/ascii-xfr -sv Y U N Y
    \ J Ascii /usr/bin/ascii-xfr -rv Y D N Y
    \
    \ AUTHOR
    \ Miquel van Smoorenburg, miquels@cistron.nl
    \ Jukka Lahtinen, walker@netsonic.fi
    \
    \ SEE ALSO
    \ minicom(1)
    \
    \ $Date: 2024/04/11 14:53:53 $ ASCII-XFR(1)

    2VARIABLE FILE
    \ Send a line .
    : send-line
    BOUNDS ?DO I C@ EMIT char-delay @ MS LOOP
    $0D EMIT $0A EMIT ;

    :R send-file FILE 2@ GET-FILE
    BEGIN ^J $/ OVER WHILE send-line line-delay @ MS REPEAT
    send-eof ;
    \ Return a line and a goon flag.
    : receive-line '(ACCEPT) CATCH 0= 2DUP + 1- C@ EOF <> OR ;

    :R receive-file 0 PAD !
    BEGIN receive-line WHILE PAD $+! ^J PAD $C+ REPEAT
    PAD $@ FILE 2@ PUT-FILE ;

    : process-arguments
    BEGIN
    1 ARG[] OVER C@ &- = IF EVALUATE ELSE FILE 2! SHIFT-ARGS THEN
    ARGC 1 > WHILE REPEAT ;

    : -h "See: man ascii-xfr" TYPE CR
    "ERROR 1001: file name missing" TYPE CR
    "ERROR 1002: -r/-s missing" TYPE CR BYE ;

    : -v "$Id: ascii-xfr.frt,v 1.6 2024/04/11 14:53:53 albert Exp albert $" TYPE CR BYE ;

    : handle-file
    FILE 2@ 2DUP OR 0= 1001 ?ERROR
    action @ DUP 0= 1002 ?ERROR
    EXECUTE ;

    : doit process-arguments handle-file ;
    \--------------------- 8< ------------------------------------
    Note:
    WANT is followed by a shopping list of facilities needed
    Real strings ("APE") used throughout.
    Make it into a turnkey with entry point `doit like so:
    $FORTH -c ascii-xfrt.frt
    Uncommented words use no arguments
    Chuck Moore comment specifications, arguments between double spaces.
    I use forward references, DEFER drives me crazy. (:F :R).

    This is fresh, it is not yet used by minicom.

    Groetjes Albert
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -
    --- Synchronet 3.20a-Linux NewsLink 1.114