From:	CRDGW2::CRDGW2::MRGATE::"SMTP::EQL.CALTECH.EDU::RANKIN"  5-JAN-1990 19:00
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Update for Fall SIG tape submission

Date:     Fri, 5 Jan 90 14:32:37 PST
From: rankin@EQL.Caltech.Edu (Pat Rankin)
Message-Id: <900105142954.22e013e2@EQL.Caltech.Edu>
Subject:  Update for Fall SIG tape submission
To: everhart@arisia.decnet

Glenn,
     This is the message I tried to send in December regarding fixes for
some of the stuff I brought to the Anaheim for the Fall'89 SIG tape.
There's a minor fix for a bug of mine and a more complicated fix to work
around a bug in RMS.  The bigger problem (which bit my EXTRACT utility
and the fairly trivial RC record counting program) is that SYS$FIND
fails to find the last record of a stream (or stream_lf or stream_cr)
format file if that record is not explicitly terminated.  ANALYZE/RMS
reports such a file to be in error, but SYS$GET (ie, normal RMS read)
handles it properly.

     This small program creates two test files, the first of which
exhibits the problem I'm describing.
--
#include <stdio.h>
main() {              /* both test1.tmp & test2.tmp receive 3 records */
    freopen("test1.tmp", "w", stdout);
    printf("this\nis a\ntest");       /*[ last record not terminated ]*/
    freopen("test2.tmp", "w", stdout);
    printf("this\nis a\ntest\n");     /* this is the way RMS wants it */
    fclose(stdout);
}
--

     The files affected are [RANKIN.EXTRACT]EXTRACT.* (& others)
and [RANKIN.MISC]RC.MAR (& RC.EXE).  The enclosed VMS_SHARE archive
contains a pair of command procedures, [.EXTRACT]PATCH_EXTRACT.COM
and [.MISC]PATCH_RC.COM, and some SUMSLP difference files for use by
the former.  To apply them, set default to your equivalent of [rankin]
(ie, one level above the two subdirectories) and unpack the VMS_SHARE
file.  Then, set default [.misc] and @patch_rc (this one is short
and will clean up after itself).  Next, set default [-.extract] and
@patch_extract (this one is longer and requires that you have VAX
Fortran available).  Finally, you'll need to manually execute the
purge and delete commands that are commented out at the bottom of
patch_extract.com.  When all is done, you should end up with the
same set of files as when you started--just newer versions of some
of them.

				Pat Rankin
				Calif. State Legislature
				rankin@eql.Caltech.EDU

ps, keep up the good work!

$! ------------------ CUT HERE -----------------------
$! This archive created by VMS_SHARE Version 7.1-X02  26-JUN-1989
$!   On 20-DEC-1989 18:34:00.71   By user RANKIN
$!
$! This VMS_SHARE Written by:
$!    Andy Harper, Kings College London UK
$! Acknowledgements to:
$!    James Gray       - Original VMS_SHARE
$!    Michael Bednarek - Original Concept and implementation
$!
$! TO UNPACK THIS SHARE FILE, EXECUTE IT  (  @name  )
$!
$! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING:
$!       1. [.EXTRACT]PATCH_EXTRACT.COM;4
$!       2. [.EXTRACT]EXTRACT_FOR.SLP;1
$!       3. [.EXTRACT]EXTRACT_MAK.SLP;1
$!       4. [.EXTRACT]EXTR_INP_FOR.SLP;1
$!       5. [.EXTRACT]FINDFILE_FOR.SLP;1
$!       6. [.EXTRACT]LINK_EXTR_COM.SLP;1
$!       7. [.MISC]PATCH_RC.COM;3
$!
$SET SYMBOL/SCOPE=(NOGLOBAL,NOLOCAL)
$f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID"))
$e="write sys$error  ""%UNPACK"", "
$w="write sys$output ""%UNPACK"", "
$ if f$trnlnm("SHARE_LOG") then w = "!"
$ goto START
$UNPACK: SUBROUTINE ! P1=filename, P2=checksum
$ if f$search(P1).eqs."" then goto file_absent
$ e "-W-EXISTS, File ''P1' exists. Skipped."
$ delete 'f'*
$ exit
$file_absent:
$ if f$parse(P1).nes."" then goto dirok
$ dn=f$parse(P1,,,"DIRECTORY")
$ w "-I-CREDIR, Creating directory ''dn'."
$ create/dir 'dn'
$ if $status then goto dirok
$ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped."
$ delete 'f'*
$ exit
$dirok:
$ w "-I-PROCESS, Processing file ''P1'."
$ def/user sys$output nl:
$ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1'
PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET(
SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:=
CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b));
LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION(
BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1);
IF g = 0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE;
MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1;
ERASE_LINE;ENDIF;ELSE IF x="-" THEN g:=0;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;p:=
"`";POSITION(BEGINNING_OF(b));LOOP r:=SEARCH(p,FORWARD);EXITIF r=0;POSITION(
r);ERASE(r);COPY_TEXT(ASCII(INT(ERASE_CHARACTER(3))));ENDLOOP;o:=GET_INFO(
COMMAND_LINE,"output_file");WRITE_FILE(b,o);ENDPROCEDURE;Unpacker;EXIT;
$ delete 'f'*
$ CHECKSUM 'P1'
$ if CHECKSUM$CHECKSUM.nes.p2 then -
 e "-E-CHKSMFAIL, Checksum of ''P1' failed."
$ ENDSUBROUTINE
$START:
$ create 'f'
X$! Source patch to update EXTRACT from v1.3 to v1.4 and rebuild extract.exe.
X$!
X$  if f$search("extract.for").nes."" then  goto got_source
X$ ! fetch source
X$       libr/text/log extract/extract=extract.for/output=extract.for
X$       libr/text/log extract/extract=extr_inp.for/output=extr_inp.for
X$       libr/text/log extract/extract=findfile.for/output=findfile.for
X$       libr/text/log extract/extract=extract.mak/output=extract.mak
X$got_source:
X$ ! update source
X$       sumslp := edit/sum
X$  sumslp extract.for/update=extract_for.slp
X$  sumslp extr_inp.for/update=extr_inp_for.slp
X$  sumslp findfile.for/update=findfile_for.slp
X$       set noon
X$  sumslp extract.mak/update=extract_mak.slp
X$  sumslp link_extract.com/update=link_extr_com.slp
X$       set on
X$!
X$ ! store revised source
X$  libr/text/log extract extract.for/module=extract.for
X$  libr/text/log extract extr_inp.for/module=extr_inp.for
X$  libr/text/log extract findfile.for/module=findfile.for
X$  libr/text/log extract extract.mak/module=extract.mak
X$  libr/text/data=reduce extract
X$!
X$ ! compile revised source (first fetch include files)
X$  define f_inc `091`093
X$  libr/text/log extract/extract=dsc.f/output=f_inc:dsc.f
X$  libr/text/log extract/extract=xabs.f/output=f_inc:xabs.f
X$  fort `091`093extract
X$  fort `091`093extr_inp
X$  fort `091`093findfile
X$  delete f_inc:dsc.f;0,xabs.f;0/since
X$!
X$ ! store new object modules
X$  libr/obj extract/repl `091`093extract
X$  libr/obj extract/repl `091`093extr_inp
X$  libr/obj extract/repl `091`093findfile
X$  libr/obj/data=reduce extract
X$!
X$ ! rebuild executable image
X$  link/nosysshr extract/lib/include=extract,-
X`009sys$library:starlet/lib,sys$input:/options
Xidentification="v1.4"
X$!
X$ ! clean up
X$! purge
X$! delete *.slp;0,*.obj;0,patch_extract.com;0
$ CALL UNPACK [.EXTRACT]PATCH_EXTRACT.COM;4 1146749957
$ create 'f'
X-    4,    5
X`009!                       vers 1.3                      "     Jul'89
X`009!                       -DECUS, Anaheim SIG tape-     "     Oct'89
X`009!                       vers 1.4                      "     Dec'89
X`009!
X-   13
X*     version 1.4, 19-DEC-1989 `091pr`093
X*           Additional code added to handle a stream file which has an
X*       unterminated final record (ie, no trailing '\n' for stream_lf).
X*       SYS$FIND fails to locate the final record, causing incorrect
X*       count and/or initial position.  Although ANALYZE/RMS considers
X*       such a file to be in error, it can be handled with SYS$GET.
X*
X-   26,   26
X`009logical         show_name,  ldummy,  was_bad,  need_input,
X     &                  stream
X-   47,   47
X     &          sts = Open_Input_File( infile(:inf_len), rabadr, stream)
X-   72,   72
X`009`009sts = Process_File( %VAL(rabadr), stream, cond)
X-   81,   81
X     &          sts = Open_Input_File( infile(:inf_len), rabadr, stream)
X-  147,  147
X      integer *4 function  Process_File ( rab, is_stream, condition )
X-  170
X`009logical         is_stream       !requires special handling for $FIND
X-  180,  180
X`009logical         manipulate_record,  stream_kludge
X-  214
X`009stream_kludge = .false.
X-  228,  228
X`009    sts = Rfa_Position( rab, nxt_rec, start, finish, is_stream)
X-  232
X`009    if ( is_stream ) then
X`009`009start = start - 1
X`009`009stream_kludge = .true.
X`009    end if
X-  241
X`009    if ( stream_kludge .and. sts ) then
X`009`009start = start + 1               !restore original value
XC             skip next stream record unless it's the first of the file
X`009`009if ( start .gt. 1 ) then
X`009`009    sts = SYS$GET( rab)
X`009`009    if ( sts .eq. RMS$_RTB )  sts = RMS$_NORMAL
X`009`009    if ( sts )  nxt_rec = nxt_rec + 1
X`009`009else
X`009`009    nxt_rec = 1         !start with first record
X`009`009end if
X`009    end if
X/
$ CALL UNPACK [.EXTRACT]EXTRACT_FOR.SLP;1 792032786
$ create 'f'
X-    3
X#       vers 1.4                                           revised, Dec'89
X-   11,   11
X`009identification="v1.4"                                           $
X/
$ CALL UNPACK [.EXTRACT]EXTRACT_MAK.SLP;1 341070050
$ create 'f'
X-   94,   94
X      integer *4 function  Open_Input_File ( filename, rabadr, stream )
X-  124
X`009logical         stream
X-  199
X`009stream = ( fab.fab$b_rfm .eq. FAB$C_STMLF
X     &        .or. fab.fab$b_rfm .eq. FAB$C_STMCR
X     &        .or. fab.fab$b_rfm .eq. FAB$C_STM )
X-  208,  208
X      integer *4 function
X     &    Rfa_Position ( rab, nxt_rec, start, finish, is_stream )
X-  228
X`009logical         is_stream       !requires special handling for $FIND
X-  233,  240
X`009record /rfa/    rfa,  prev_rfa,  rec(cACHE_SIZ),
X     &                  big(cACHE_SIZ),  huge(cACHE_SIZ)
X`009integer         recpos,  bigpos, hugepos
X`009logical         got_start,  chk_stream,  stream_kludge
X`009integer *4      rec_cnt,  sts
XC     functions:
X`009integer *4      SYS$FIND,  SYS$GET,  SYS$REWIND,  ReRead_Stream
X`009intrinsic       MAX,  MIN
X
XC     kludge for SYS$FIND vs. unterminated final record
X`009chk_stream = is_stream
X`009if ( chk_stream ) then
X`009    prev_rfa.block  = 0
X`009    prev_rfa.offset = 0
X`009end if
X`009stream_kludge = .false.
X-  251,  251
X`009    if ( chk_stream ) then
X`009`009if ( sts .eq. RMS$_EOF ) then
X`009`009    sts = ReRead_Stream( rab, prev_rfa)
X`009`009    stream_kludge = ( (sts .and. 1).ne. 0 )
X`009`009    chk_stream = .false.
X`009`009else
X`009`009    prev_rfa.block  = rab.rab$l_rfa0
X`009`009    prev_rfa.offset = rab.rab$w_rfa4
X`009`009end if
X`009    end if
X`009    if ( sts )  rec_cnt = rec_cnt + 1
X
X-  313,  318
XC         setup position for next read
X`009    if ( stream_kludge .and. start .eq. rec_cnt ) then      !"/tail=1"
X`009`009rfa = prev_rfa                  !back up to previous record
X`009    else
X`009`009stream_kludge = .false.         !no additional fixup neeed
X`009    end if
X`009    if ( stream_kludge .and. rfa.block .eq. 0 ) then
X`009`009sts = SYS$REWIND( rab)          !start at top of file
X`009`009stream_kludge = .false.         !don't get a record below
X`009    else
XC             set rfa and fetch record (into position for next sequential re
Vad)
X`009`009rab.rab$l_rfa0 = rfa.block
X`009`009rab.rab$w_rfa4 = rfa.offset
X`009`009rab.rab$b_rac = RAB$C_RFA       !access via rfa
X`009`009sts = SYS$FIND( rab)            !locate the record
X`009`009rab.rab$b_rac = RAB$C_SEQ       !restore sequential access
X`009    end if
X`009    if ( stream_kludge .and. sts ) then
X`009`009sts = SYS$GET( rab)     !read a record iff we have backed up one
X`009`009if ( sts .eq. RMS$_RTB )  sts = RMS$_NORMAL  !ignore rec too big
X`009    end if
X-  526
X
X
X
X
X      integer *4 function  ReRead_Stream ( rab, prev_rfa )
X`009!
X`009!   Stream format files may have an unterminated record at the end
X`009!   that SYS$FIND will miss.  ANALYZE/RMS reports this situation
X`009!   as an error, but SYS$GET handles it just fine.
X`009!
X`009implicit none
XC     called by:
X*       function        Process_File
XC     constant:
X`009include '($RMSdef)/list'                !rms status values
X`009include '($RABdef)/list'                !rms Record Access Block defs
X`009structure /rfa/
X`009    integer *4      block
X`009    integer *2      offset
X`009end structure !rfa
XC     input:
X`009record /rabdef/ rab
X`009record /rfa/    prev_rfa
XC     local:
X`009integer *4      sts
XC     functions:
X`009integer *4      SYS$GET,  SYS$FIND,  SYS$REWIND
X
XC     set rfa and fetch record (into position for next sequential read)
X`009if ( prev_rfa.block .ne. 0 ) then
X`009    rab.rab$l_rfa0 = prev_rfa.block
X`009    rab.rab$w_rfa4 = prev_rfa.offset
X`009    rab.rab$b_rac = RAB$C_RFA           !access via rfa
X`009    call SYS$FIND( rab)                 !locate previous record
X`009    rab.rab$b_rac = RAB$C_SEQ           !restore sequential access
X`009    call SYS$GET( rab)                  !read previous record
X`009else    !couldn't find first record, but it may actually be there
X`009    call SYS$REWIND( rab)               !there was no previous record
X`009end if
X`009sts = SYS$GET( rab)                 !attempt to read another record
X`009if ( sts .eq. RMS$_RTB )  sts = RMS$_NORMAL
X
X`009ReRead_Stream = sts
X`009return
X      end !of ReRead_Stream
X/
$ CALL UNPACK [.EXTRACT]EXTR_INP_FOR.SLP;1 975614788
$ create 'f'
X-  137
X`009`009IF ( (nam.nam$l_fnb .AND. NAM$M_PPF).NE. 0 )
X     &                  do_search = .FALSE.
X/
$ CALL UNPACK [.EXTRACT]FINDFILE_FOR.SLP;1 745360117
$ create 'f'
X-    4,    4
Xidentification="v1.4"
X/
$ CALL UNPACK [.EXTRACT]LINK_EXTR_COM.SLP;1 1279788955
$ create 'f'
X$! Revise RC to handle stream files which may have unterminated last record.
X$!
X$ sumslp := edit/sum
X$ sumslp rc.mar/update=sys$input:
X-   17,   18
X;`009Check for RFM=UDF to prevent infinite loop;
X;`009New _msg_setup macro to clean-up error message contortions.
X;   `091pr`093 Dec'89
X;`009Use SYS$GET instead of SYS$FIND for stream format files; it's
X;`009possible to have an unterminated final record that $FIND will
X;`009miss.  (ANALYZE/RMS considers such a file to be in error, but
X;`009$GET handles it properly.)  `091Untested for records of 64K or more.`09
V3
X-  295,  297
X`009movb`009fab+FAB$B_RFM, r0`009;get record format
X`009cmpb`009#FAB$C_STMLF, r0`009;check rfm for stream_lf
X`009beql`00941$
X`009cmpb`009#FAB$C_STMCR, r0`009;or stream_cr
X`009beql`00941$
X`009cmpb`009#FAB$C_STM, r0`009`009;or stream `091_crlf`093
X`009beql`00941$
X`009bbc`009#FAB$V_BLK, fab+FAB$B_RAT, 42$`009;check record attributes
X;     special handling for files containing non-block-spanned records ($find
V bug)
X41$:`009subl2`009#`094d512, sp`009`009;buffer for one block (512 bytes)
X/
X$!
X$ macro/nodebug rc
X$ link/notraceback rc
X$!
X$ purge rc.*
X$ delete rc.obj;,'f$environ("PROCEDURE")'
$ CALL UNPACK [.MISC]PATCH_RC.COM;3 477170490
$ EXIT
---end of message---
