home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 35 Internet
/
35-Internet.zip
/
goswish5.zip
/
MKDCT.CMD
< prev
next >
Wrap
OS/2 REXX Batch file
|
1999-02-17
|
55KB
|
1,860 lines
/* create a "description cache" for use by the GoSWISH script */
/* Note:
by default, files are assumed to be non-html text files.
Exceptions:
Files with extensions in the Htmls list are assumed to be HTML documents
Files with extensions that appear in the NoContents variable
(either the user-set NoContents variable, or the NoContents entry
in the Swish Configuration file) are assumed to be non-text files.
(descriptions are not generated for non-text files)
*/
/* -------- User Changable Parameters -------------*/
/* Files with these extensions are assumed to be HTML files */
htmls=" HTM HTML SHTML SHTM SHT HTML-SSI HTM-SSI "
/* Files with these extensions are assumed to NOT be plain-text files --
THIS IS ONLY USED if you are using the "list of URLS" option --
if you are reading from a SWISH index, the NOCONTENTS parameter is used */
nocontents="JPG GIF ZIP XBM "
/* Directory specific "description files". These should contain
descriptions of files within the directory. */
descript_file="DESCRIBE.TXT"
/* the default SWISH configuration file */
defcon="SAMPLES.CON"
/* the default list of urls (text mode) */
deftxt="SRCHCSH.IN"
/* the default "description-cache" file */
defdesc="SAMPLES.DCT"
/* the default "WWW" (HTML) directory */
defdir="\WWW"
/* the default "directory specific file-description file" */
defdescribe='DESCRIBE.TXT'
/* This is the character used to signal "continuation of a description"
I.e. (assuming continuation_flag='|'
FOOBAR.TXT This is the descripton of foobar.txt
| And this is the second line.
Note that the | should be the first non space character */
continuation_flag='|'
/* -------- End of User Changable Parameters -------------*/
crlf='0d0a'x
call initit
say " "cy_ye ' This is the GoSWISH "description-cache file creator". ' normal
say " "
say ' This program requires either a SWISH index file, or a "list of URLS".'
say " "
aa=yesno(' Create (C), or modify (M), a description cache','CREATE MODIFY')
if aa=1 then do
call editit
say " bye "
exit
end /* Do */
aa=yesno(" Use a SWISH index (S), or a text index (T) ",'SWISH TEXT')
dtype=yesno(' Create a regular (R), or a structured (S) ".DCT" file ','Regular Structured')
if aa=0 then
call get_confile
else
call get_txtfile
call get_filelist_info
call get_outname
say reverse " ------------------------------ " normal
say " Saving descriptions for " filelist.0 " files "
latestd.=''
latestd.!dir=' ' /* used to retain most recent dir-specific desc file */
desc.0=filelist.0
do m=1 to desc.0
desc.m=translate(filelist.m.!original,'/','\')
desc.m.!title=filelist.m.!title
desc.m.!size=filelist.m.!size
desc.m.!summary=strip(make_summary(filelist.m,filelist.m.!type,2))
desc.m.!sumtype=yaman /*0-none, 1=created, 2=from dir-specific desc file 3=entered by hand*/
if (m//1000)=1 then say "::reading "m" ) "left(desc.m,min(length(desc.m),100))
end /* do */
if dtype=0 then do /* regular */
div=' &^%^& '
div2=' #$*~~#$* '
allf=""
foo=stream(outname,'c','open write')
if translate(foo)<>'READY:' then do
say "ERROR: could not open " outname
exit
end /* do */
do ii=1 to desc.0
aa=desc.ii.!sumtype||div||desc.ii||div||desc.ii.!title||div||desc.ii.!size|| ,
div||desc.ii.!summary
allf=allf||aa
if ii<>desc.0 then allf=allf||div2
if length(allf)>10000 then do
aba=charout(outname,allf)
allf=''
end
if (ii//1000)=1 then say "::writing entry # "ii
end /* do */
if length(allf)>0 then aba=charout(outname,allf)
sike=stream(outname,'c','close')
if translate(sike)="READY:" then
say "Description cache file "outname " successfully written."
else
say " Problem writing description cache file "outname
sike=stream(outname,'c','close')
end
else do
foo=build_desc_cache(outname,'Descriptions from 'daindx,1)
if foo=1 then
say "Description cache file "outname " successfully written."
else
say " Problem writing description cache file "outname
end
exit
/**************************/
get_outname:
say reverse " ------------------------------ " normal
n2:
say " Enter the name to use for the "DCT" file: "
call charout ,' (default= ' defdesc ')' bold ' ? ' normal
pull outname ; if outname="" then outname=defdesc
if fdescribe="?" then do
say ' This ".DCT" (description-cache file) is used to store the file summaries'
say ' You can include a reference to this file in the "search form" documents that'
say ' use the "search documents" mode of GoSwish '
say ' (such as the "search form" documents generated by the "create index" mode of GoSWISH)'
signal n4a
end /* Do */
outname=strip(outname)
adir=filespec('D',outname)||filespec('P',outname)
if adir="" then adir=directory()
if dir_exists(strip(adir,'t','\'))=0 then do
say " Could not find directory: " reverse adir normal
say " Please re-enter .... "
signal n2
end
if pos('.',outname)=0 then outname=outname'.dct'
/* rename prior dct file */
if stream(outname,'c','query exists')<>'' then do
iii=lastpos('.',outname)
if iii=0 then do
bkfile=outname'.bak'
end /* do */
else do
bkfile=left(outname,iii)||'bak'
end /* do */
say "Backing up old version to: "bkfile
yow=sysfiledelete(bkfile)
buzz=charin(outname,1,stream(outname,'c','query size'))
foo=charout(bkfile,buzz,1)
foo=stream(bkfile,'c','close')
foo=stream(outname,'c','close')
foo=sysfiledelete(outname)
if foo<>0 then do
say 'Problem ('foo') could not delete old version of ' outname
exit
end /* do */
end /* backing up old version */
n4a:
say " "
say ' Enter the name of the "directory specific" 'bold' file-description file. 'normal
call charout ,' (default= ' defdescribe ', ?=HELP, .=None)' bold ' ? ' normal
pull fdescribe ; if fdescribe="" then fdescribe=defdescribe
else
if fdescribe="?" then do
say ' The "directory specific"' bold' file-description file'normal' is used to assign '
say " explicit descriptions to any file. "
say ' For all files being "described", a 'bold' file-description file'normal " in it's " bold"own"normal
say " directory is examined; and if a matching entry is found, the associated"
say " description is used."
say " Entries in the file-description file should be organized as:"
say " FILE1.xxx a description "
say " Examples: "
say cy_ye " " normal " file2.yyy This is the YYY file "
say cy_ye " " normal " foobar.htm This is the classic FOOBAR file. In this case we use"
say " | a 2 line description (the | is a continuation flag)"
signal n4a
end /* Do */
fdescribe=translate(fdescribe,'\','/')
if pos('\',fdescribe)>0 then do
say " The file-description file is " bold" directory-specific "normal
say " Please reenter (and do NOT include a path) "
signal n4a
end
return 0
/**************************/
/* read swish configuration and index files */
get_confile:
say reverse " ------------------------------ " normal
n2a:
do forever /* loop in case of ? response */
say " Enter the fully qualifed name of the reference SWISH configuration file."
call charout , ' (?=list files, default=' defcon ')' bold ' ? ' normal
pull aconfile ; aconfile=strip(aconfile)
if aconfile="" then
confile=defcon
else
confile=aconfile
if abbrev(confile,"?")=1 then do
thisdir=directory()
say
say reverse ' List of files in: ' normal bold thisdir normal
do while queued()>0
pull .
end /* do */
parse var aconfile "?" aget . ; aget=strip(aget)
if aget="" then aget="*.*"
'@DIR /b '||strip(thisdir,'t','\')'\'aget ' | rxqueue'
foo=show_dir_queue('*')
iterate
end /* do */
if confile='' then iterate
if stream(confile,'c','query exists')='' then do
say bold"Sorry,"normal" no such file: "confile
iterate
end /* do */
leave
end /* do */
/* now get info */
foo=afileread(confile)
if clines.0=0 then do
say " Could not find configuration file: " reverse confile normal
say " Please re-enter .... "
signal n2a
end
/* find the IndexFile entry, and the ReplaceRules entries. */
nreps=0 ; nocontents=' '
do mm=1 to clines.0
aline=strip(translate(clines.mm))
select
when abbrev(aline,'INDEXFILE')=1 then do
parse var aline . daindx . ; daindx=strip(daindx)
end
when abbrev(aline,'REPLACERULES') then do
nreps=nreps+1 ; aline=translate(aline,' ','"'||"'")
parse var aline . . reprules.nreps.!original reprules.nreps.!new .
end
when abbrev(aline,'NOCONTENTS')=1 then do
parse var aline . nocontents . ; nocontents=strip(nocontents)
end
otherwise nop
end
end /* Do */
daindx0=stream(daindx,'c','query exists')
if daindx0=" " then do
say " Problem: could not find SWISH index file: " daindx
exit
end
say "Using SWISH index file: "daindx
do mm=1 to nreps
a1=reprules.mm.!Orig ; a2=reprules.mm.!new
reprules.mm.!orig=strip(translate(a1))
reprules.mm.!new=strip(translate(a2))
end /* do */
reprules.0=nreps
call get_swifile /* read the swish index file, get file names */
say "# files to index:: " nfiles
return nfiles
/**************************/
/* read text (user created) configuration and index files */
get_txtfile:
say reverse " ------------------------------ " normal
n3a:
say " Enter a text file containing a list of URLs (? for HELP) "
call charout , ' (default=' deftxt ')' bold ' ? ' normal
pull txtfile
if txtfile="" then txtfile=deftxt
if txtfile="?" then do
say " Each line of the file should contain entries of the form: "
say cy_ye " " normal ' relative_url "Short Description " size filename '
say " Where: "
say " " bold " relative_url "normal "is required. It is used as the link to the file. "
say " " bold ' "short description" ' normal ' is optional. If included, it must be within "'
say " " bold " size "normal" is optional; it's the size in bytes "
say " " bold "filename" normal 'is optional. It is the fully qualified name of the file.'
say " If not specified, the URL is assumed to refer to a file that is "
say " relative to the WWW (HTML) directory "
say bold "Examples: " normal
say cy_ye " " normal '/samples/SAMPMBOX.HTM "Sample Message Sender for SRE-http" 1390 '
say cy_ye " " normal '/samples/SAMPOPT1.HTM "Sample of OPTIONS Keyphrase for SRE-http" 2728'
say " "
signal n3a
end
/* now get info */
foo=afileread(txtfile)
if clines.0=0 then do
say " Could not find list of URLS: " reverse txtfile normal
say " Please re-enter .... "
signal n3a
end
n3b:
say " Enter the name of the WWW (HTML) directory: "
call charout , ' (default=' defdir ')' bold ' ? ' normal
pull datadir
if datadir="" then datadir=defdir
datadir=strip(datadir,'t','\')
if dir_exists(datadir)=0 then do
say " Could not find directory: " datadir
signal n3b
end
/* process file list */
Say " Processing " txtfile
nfiles=0
do nf=1 to clines.0
baa=clines.nf
if baa=" " | abbrev(strip(baa),';')=1 then iterate
nfiles=nfiles+1
parse var baa aa '"' atitle '"' asize absfile .
afil=translate(strip(word(aa,1)))
filelist.nfiles.!original=afil
filelist.nfiles.!title=atitle
filelist.nfiles.!size=asize
if absfile <> " " then
filelist.nfiles=absfile
else
filelist.nfiles=datadir||strip(aa,'l','\')
filelist.nfiles=translate(filelist.nfiles,'\','/')
if filelist.nfiles.!size=" " | datatype(filelist.nfiles.!size)<>"NUM" then do
filelist.nfiles.!size=dosdir(filelist.nfiles,'S')
end
end /* do */
filelist.0=nfiles
return nfiles
/****************************/
/* given a filefilst, get descriptions */
get_filelist_info:
/* determine type of file: 2=text, 1=html, 0=non-text */
htmls=translate(translate(htmls),' ','.')
nocontents=translate(translate(nocontents),' ','.')
do mm=1 to filelist.0
aff=filelist.mm
filelist.mm.!type=2 /* assume it's text */
foo=lastpos('.',aff)
if foo=0 then iterate
anext=strip(translate(substr(aff,foo+1)))
if wordpos(anext,htmls)>0 then do
filelist.mm.!type=1
iterate
end
if wordpos(anext,nocontents)>0 then filelist.mm.!type=0
end /* do */
return 0
/* -------------------- */
/*********************************/
/* rudimentary edit of a description file */
editit:
say " "
say reverse " ------------------------------ " normal
iff=1
n2b:
do forever
say " Enter the name of the description-cache file you want to modify."
call charout ,' (?=list files, default= ' defdesc ')' bold ' ? ' normal
pull aa ; aa=strip(aa)
if aa="" then do
outname=defdesc
leave
end
if abbrev(aa,"?")=1 then do
thisdir=directory()
say
say reverse ' List of files in: ' normal bold thisdir normal
do while queued()>0
pull .
end /* do */
parse var aa "?" aget . ; aget=strip(aget)
if aget="" then aget="*.*"
'@DIR /b '||strip(thisdir,'t','\')'\'aget ' | rxqueue'
foo=show_dir_queue('*')
iterate
end /* do */
outname=aa
if pos('.',outname)=0 then outname=strip(outname)||'.dct'
leave
end /* do */
outname=strip(outname)
if stream(outname,'c','query exists')='' then do
say " Could not find description cache file: " reverse outname normal
say " Please re-enter .... "
signal n2b
end
newtype=yesno(' Save as a regular (R), or a structured (S) .DCT file ','Regular Structured')
if newtype=1 then do
say bold"Enter 80 character description of this index"normal
call charout," "reverse"?"normal
parse pull dctindx.!message
say "Message: " dctindx.!message
end
/* is it a regular or a structured dct file */
div=' &^%^& '
div2=' #$*~~#$* '
adfil=strip(outname)
ii=0
goofy=charin(adfil,1,10)
if abbrev(goofy,'#GOSWISH')=1 then do
say ' Reading a structured DCT file '
istat=load_desc_cache(adfil)
if istat<0 then do /* problem reading structured dct file */
astats.1 = "Not a GoSWISH descriptive-summaries cache file"
astats.2 = "File corrupted (problem with terminiator) "
astats.3 = "Corrupted GoSWISH description-cache file (improper termination of index) "
astat=strip(abs(istat))
Say "Error: " astats.astat
exit
end
say outname " has: # records= " dctindx.0 ', key length: ' dctindx.!keylen', offset= 'dctindx.!Offset
say "Message: " dctindx.!message
incache=DCTINDX.0
cache_type=2 ; scachename=adfil
end /* structured dct */
else do /* regular dct */
say ' Reading a regular DCT file '
goofy=charin(adfil,1,stream(adfil,'c','query size'))
i1=1 ; lengoofy=length(goofy) ;isleave=0
do forever
i2=pos(div2,goofy,i1)
if i2=0 then do
isleave=1
i2=lengoofy
end /* do */
aa=substr(goofy,i1,i2-i1)
i1=i2+length(div2)
ii=ii+1 ; desc.0=ii
if (ii//500)=1 then say "... reading entry #" ii
parse var aa desc.ii.!sumtype (div) desc.ii (div) desc.ii.!title (div) ,
desc.ii.!size (div) desc.ii.!SUMMARY
if (isleave=1) then leave
end /* read lines from descirpfile */
cache_type=1
say " ... "ii " entries found."
end /* regular dct */
if cache_type=2 then do /* copy structured dct to dcache */
bodyat=dctindx.!offset+1
fsize=stream(scachename,'c','query size')
goofy=charin(scachename,bodyat,1+fsize-(bodyat+8))
div5='05'x
i1=1 ;ii=0 ;leaveit=0
do forever
ii=ii+1
if (ii//1000)=1 then say " ... reading entry #"ii
do rr=1 to 6 /* six items per entry */
i2=pos(div5,goofy,i1)
if i2=0 then do
leaveit=1
leave
end /* do */
abb.rr=substr(goofy,i1,i2-i1)
i1=i2+1
end /* do */
if leaveit=1 then leave
desc.ii.!sumtype=abb.2 ; desc.ii=abb.3
desc.ii.!title=abb.4 ; desc.ii.!size=abb.5
desc.ii.!summary=abb.6
dcachel.II=desc.II
/* parse var goofy dlen (div5) desc.ii.!sumtype (div5) desc.ii (div5) desc.ii.!title (div5) ,
desc.ii.!size (div5) desc.ii.!summary (div5) goofy */
end
desc.0=DCTINDX.0 ; DCACHEL=0=desc.0
drop goofy
end /* do */
if cache_type=1 then do
do mm=1 to desc.0 /* copy urls to a url array */
dcachel.mm=desc.mm
end /* do */
dcachel.0=desc.0
incache=desc.0
end /* do */
asknams:
if yesno(' Would you like to list the names of these entries ')=1 then do
SAY " " CY_YE " File Name :: Title " normal
iat=1
do forever
iat=show_entries(iat)
if iat>desc.0 then leave
call charout , cy_ye ' (hit any key to continue, X stop) ' normal
foo=sysgetkey("noecho") ; say " "
IF translate(FOO)='X' then LEAVE
end
end
sq=1
do forever
thedef=desc.iff
if iff=1 | isq=1 then do
say " Currently viewing "iff " of "desc.0 " entries."
say " Enter the " reverse " name " normal " you wish to modify. Or, "
say bold " Space=modify, UP and DOWN arrow= previous and next, ESC=Exit "
say ' ?=Help, Ctrl-Z=abort, nn = to entry #nn, @=view neighborhood ' normal
end
isq=0
/* find record for thedef */
call charout, bold||iff||')'||normal
todo=translate(stringin2(thedef,iff))
if length(todo)=0 then do
iff=min(iff+1,desc.0)
iterate
end
if d2c(27)=todo then do
say
rt=yesno("Review\Save&Exit\Quit",'Review Save Quit')
if rt="2" then exit
if rt=1 then leave
signal asknams
end
if d2c(26)=todo then exit
todo=strip(todo)
if todo='?' then do
say
isq=1 ; iterate
end
if todo="<" | todo=',' then do
iff=max(iff-1,1)
iterate
end
if datatype(todo)='NUM' then do
iff=max(min(todo,desc.0),1)
iterate
end /* do */
if todo='@' then do
say
ifoo=show_entries(iff-8)
iterate
end /* do */
if todo='' then todo=thedef /* lookup an entry */
iff2=0
do ll=1 to desc.0
if pos(todo,desc.ll)>0 then do
iff2=ll
leave
end /* do */
end /* do */
if iff2=0 then do
say " No entry for: " todo ; say
iterate
end /* Do */
iff=iff2
say " "
say cy_ye " .......................... " normal
say reverse desc.iff normal " ( size= " desc.iff.!size
say bold "Title:" normal desc.iff.!title
ogit=desc.iff.!sumtype
dathing=''
select
when ogit=0 then say " "
when ogit=2 then say bold 'Summary derived from directory-specific descriptions file'normal
when ogit=3 then say "Summary specified by administrator"
otherwise say bold" Summary generated from file contents"normal
end /* select */
if ogit<>0 then do
dathing=desc.iff.!summary
dathing=fixda(dathing)
end
say dathing
say cy_ye " .......................... " normal
which=yesno("Change the summary? ")
if which=1 then do
say " Enter new descriptive summary: "
dathing=getda()
desc.iff.!summary=dathing
desc.iff.!sumtype=3
end
end
iii=lastpos('.',outname)
if iii=0 then do
bkfile=outname'.bak'
end /* do */
else do
bkfile=left(outname,iii)||'bak'
end /* do */
say "Backing up old version to: "bkfile
yow=sysfiledelete(bkfile)
buzz=charin(outname,1,stream(outname,'c','query size'))
foo=charout(bkfile,buzz,1)
foo=stream(bkfile,'c','close')
foo=stream(outname,'c','close')
foo=sysfiledelete(outname)
if foo<>0 then do
say 'Problem ('foo') could not delete old version of ' outname
exit
end /* do */
dds.0="Regular" ;dds.1="Structured"
say " Saving Changes to "dds.newtype " DCT file = " outname
if newtype=1 then do
foo=build_desc_cache(outname,dctindx.!message,1)
if foo=1 then
say "Description cache file "outname " successfully written."
else
say " Problem writing description cache file "outname
end
else do /* regulare */
allf=''
do ii=1 to desc.0
aa=desc.ii.!sumtype||div||desc.ii||div||desc.ii.!title||div||desc.ii.!size|| ,
div||desc.ii.!summary
allf=allf||aa
if ii<>desc.0 then allf=allf||div2
end /* do */
fo=stream(outname,'c','close')
sike=charout(outname,allf,1)
if sike<>0 then
say "Problem: "sike". Could not write new version of "outname
else
say "Description cache file "outname " successfully written."
end /* do */
exit /******* END OF EDITIT *******/
getda:
say " Enter several lines of text, a blank lines signals end "
poo=""
do forever
call charout ," ? "
parse pull astuff
if astuff="" then leave
if poo='' then
poo=astuff
else
poo=poo||crlf||astuff
end
return poo
fixda:procedure expose crlf
parse arg dathing
dathing=space(translate(dathing,' ','090a0d001a'x))
aa="" ; ict=0
mxsize=75
mxsize=mxsize-5
do mm=1 to words(dathing)
aw=word(dathing,mm)
if ict+length(aw)>mxsize then do
aa=aa||crlf
ict=0
end
aa=aa||' '||aw
ict=ict+length(aw)+1
end
return aa
/* -------------------- */
/* choose between 3 alternatives (by default,a yes or no ),
return 1 if yes (or the first alternative in the altans list) */
yesno:procedure expose normal reverse bold
parse arg amessage , altans
if altans<>"" then do
w1=strip(word(altans,1))
w2=strip(word(altans,2))
if words(altans)>2 then w3=strip(word(altans,3))
a1=left(w1,1) ; a2=left(w2,1) ; a3=left(w3,1)
a1a=substr(w1,2) ; a2a=substr(w2,2) ; a3a=substr(w3,2)
aynn=' '||bold||a1||normal||a1a||'\'||bold||a2||normal||a2a
if words(altans)>2 then aynn=aynn'\'||bold||a3||normal||a3a
end
else do
a2='Y' ; a2a='es'
a1='N' ; a1a='o'
aynn=' '||bold||a1||normal||a1a||'\'||bold||a2||normal||a2a
end /* Do */
do forever
foo1=normal||reverse||amessage||normal||aynn||' 'normal
call charout,foo1
anans=translate(sysgetkey('echo'))
if abbrev(anans,a1)=1 then do
say
return 0
end
if abbrev(anans,a2)=1 then do
say
return 1
end
if abbrev(anans,a3)=1 then do
say
return 2
end
call charout,'0d'x
end
/*********/
/* show stuff in queue as a list */
show_dir_queue:procedure expose qlist.
parse arg lookfor
nq=queued()
ibs=0 ; mxlen=0
do ii=1 to nq
pull aa
if pos(lookfor,aa)=0 & lookfor<>'*' then iterate
ibs=ibs+1
blist.ibs=aa
mxlen=max(length(aa),mxlen)
end /* do */
arf=""
do il=1 to ibs
anam=blist.il
arf=arf||left(anam,mxlen+2)
if length(arf)+mxlen+2>75 then do
say arf
arf=""
end /* do */
end /* do */
if length(arf)>1 then say arf
say
return 1
/*********************************************************/
/* read swish file, create a file list (uses reprules found in con file */
get_swifile:
nfiles=get_swish_filelist(daindx)
if nfiles<1 then do
foo=is_error("Error: not a swish index file: "nfiles)
return 0
end
/* convert url style names back to original files */
do nf=1 to nfiles
afil=filelist.nf.!original
do il=1 to reprules.0 /* convert to fully qualified names */
if abbrev(afil,reprules.il.!new)=1 then do
aa=reprules.il.!original
bb=substr(afil,1+length(reprules.il.!new))
aa=aa||bb
leave
end /* Do */
end /* do */
filelist.nf=translate(aa,'\','/')
end /* do */
return nfiles
/***********************/
/* read entry names (files, or replacerule'd files, from a 1.3 swish index.
Call as
nfiles=get_swish_filelist(swish_index_file)
where
nfiles: # of files or an error code
and
filelist. is an "expose" stem containing these entries (in "reverse" order),
with tails
n.!original -- the entry name in the index
n.!title -- it's title
n.!size -- it's size
and with
filelist.0=nfiles (assuming no error, else filelist.0=0)
The error codes are:
-1 -- could not file swish_index_file
-2 -- is not a swish_index_file (first line does not look like "# SWISH format 1.3"
-3 -- could not find file count in swish_index_file
-4 -- could not open swish_index_file
-5 -- not a proper 1.3 or 1.2 index file (did not end in a '0a'x)
-6 -- file does not contain nfile entries
-7 -- file contains nfiles-1 entries, but could not find nfile'th entry
-8 -- it's a swish index, but not a 1.1, 1.2 or a 1.3 swish index
-9 -- same as -8
*/
get_swish_filelist:procedure expose filelist.
parse arg filename
cr='0a'x
filelist.0=0
filelen=stream(filename,'c','query size')
if filelen=0 | filelen='' then return -1
aa=stream(filename,'c','open read')
if translate(aa)<>'READY:' then return '-4 '
chunk=charin(filename,1,min(filelen,1000))
parse var chunk aline (cr) chunk
parse upper var aline a1 a2 a3 verswi dpg
verswi=strip(verswi)
if strip(a2)<>'SWISH' | strip(a3)<>'FORMAT' then return -2 /* not a swish file,give up*/
nfiles=0
do mm=1 to 100 /* read lines until you find # Counts: 6193 words, 100 files */
parse var chunk aline (cr) chunk
parse upper var aline . a1 . ',' a2 .
if a1="COUNTS:" then do
nfiles=a2
leave
end /* do */
end /* do */
if nfiles=0 then return -3
say "SWISH ver "verswi " file " filename " has " nfiles " entries "
if verswi=1.1 then signal is11
if verswi=1.2 then signal is12
if wordpos(verswi,'1.2 1.3')=0 then return -9
/* try this sized chunk, up it if not big enough */
perfile=220
tryagain: /* jump here to try again */
nget=perfile*nfiles
ifrom=max(1,1+filelen-nget) /* get chunk starting here */
chunk=charin(filename,ifrom,nget)
if right(chunk,1)<>'0a'x then return -5 /* 1.3 always ends in '0a'x */
nget2=length(chunk)
ii=lastpos('0a'x,chunk,nget2-1) /* get beyoud property names */
ii2=lastpos('0a'x,chunk,ii-1) /* and some other number stuff */
/* now scan back in chunk, parsing on '0000'x (which seems to signal "end of entry" */
do jj=1 to nfiles-1
ii2=lastpos('0000'x,chunk,ii2-1)
if ii2=0 then do /* perhaps didn't get enough info ? */
if ifrom=1 then return -6 /* can't get more? give up */
perfile=perfile*2 /* so get a bigger chunk this time */
leave
end /* do */
kj=pos('0a'x,chunk,ii2+1)
baa=substr(chunk,ii2,kj-ii2)
baa=strip(translate(baa,' ','00090d0a'x))
parse var baa aa '"' atitle '"' asize .
filelist.jj.!original=translate(strip(aa))
filelist.jj.!title=atitle
filelist.jj.!size=asize
end /* do */
if ii2=0 then signal tryagain /* rexx can be buggy when signaling from a do loop */
/* last one is tricky -- can't search for 0000 */
do forever /* exit via a return or a signal */
ii2=lastpos('0a'x,chunk,ii2-2)
if ii2=0 then do /* perhaps didn't get enough info ? */
if ifrom=1 then return -7 /* can't get more? give up */
perfile=perfile*2 /* so get a bigger chunk this time */
leave
end /* do */
isa=c2d(substr(chunk,ii2+1,1))
if isa>31 then do
kj=pos('0a'x,chunk,ii2+1)
baa=substr(chunk,ii2,kj-ii2)
baa=strip(translate(baa,' ','00090d0a'x))
parse var baa aa '"' atitle '"' asize .
filelist.nfiles.!original=translate(strip(aa))
filelist.nfiles.!title=atitle
filelist.nfiles.!size=asize
filelist.0=nfiles
return nfiles
end
end /* do */
signal tryagain /* only way to get here is by ii2=0 */
/* ----------------------- */
is11: /* jump here if 1.1 format */
/* count lines in the file */
call linein filename,1,0
ndo=0
do until lines(filename)=0
foo=linein(filename)
ndo=ndo+1
end /* do */
/* now get the lines ndo-nfiles to ndo-1 */
call linein filename,1,0
i1=1
do ij=1 to ndo-(i1+nfiles)
foo=linein(filename)
end /* do */
do nf=1 to nfiles /* extract the filenames */
baa=linein(filename)
baa=strip(translate(baa,' ','00090d0a'x))
parse var baa aa '"' atitle '"' asize .
afil=translate(strip(word(aa,1)))
filelist.nf.!original=afil
filelist.nf.!title=atitle
filelist.nf.!size=asize
end /* do */
filelist.0=nfiles
return nfiles
/* ----------------------- */
is12: /* jump here if 1.2 format */
/* count lines in the file */
call linein filename,1,0
ndo=0
do until lines(filename)=0
foo=linein(filename)
ndo=ndo+1
end /* do */
/* now get the lines ndo-nfiles to ndo-1 */
call linein filename,1,0
i1=1
do ij=1 to (ndo-1)-(i1+nfiles)
foo=linein(filename)
end /* do */
do nf=1 to nfiles /* extract the filenames */
baa=linein(filename)
baa=strip(translate(baa,' ','00090d0a'x))
parse var baa aa '"' atitle '"' asize .
afil=translate(strip(word(aa,1)))
filelist.nf.!original=afil
filelist.nf.!title=atitle
filelist.nf.!size=asize
end /* do */
filelist.0=nfiles
return nfiles
/***************/
/* ------------------------------------- */
/* create summary info: from explicit description in fdescribe (DESCRIBE.TXT)
or by parsing contents of file
afilename: fully qualified filename to investigate
atype: 1- html, 2-non-html text, 0-non text (of file)
asummary: 1- pre-existent only (in describe.txt),
2-create if necessary
returns a text or html summary, or a numeric code:
1= File not available
2= Summary not available
3= Explicit summary not available
4= Error in routine -- no summary available
yaman is also returned:
0-no description, 1=created, 2=explicit (from describe.txt, or <META> )
*/
make_summary:procedure expose yaman atitle asize fdescribe latestd. comment_flag continuation_flag swish_version
parse arg afilename,atype,asummary
gmess.1=' File not available'
gmess.2=' Summary not available'
gmess.3=' Summary not available'
gmess.4=' No summary available'
yaman=0
eek=stream(afilename,'c','query exists') /* check for existence*/
if eek="" then return gmess.4 /* error */
/* check in directory-specific description file (I.E.; describe.txt) */
if fdescribe<>" " then do
checkd=filespec('d',afilename)||filespec('p',afilename)
checkd=translate(checkd,'\','/')
checkd=strip(checkd,'t,','\')||'\'
if checkd<> latestd.!dir then do
call make_desc(checkd) /* saves latestd.filename=a summary */
latestd.!dir=checkd
end
fnm=strip(translate(filespec('n',afilename))) /* check the descriptions, and return match if found */
if latestd.fnm<>'' then do /* got a match, use it */
yaman=2
return latestd.fnm
end /* do */
end /* check description file */
/* no directory-specific summary -- perhaps create summary from file contents ? */
select
when atype=0 | asummary<2 then /* not text, or not "create description */
return gmess.2
when atype=2 then do /* non-html text, create mode */
alen=min(chars(afilename),300)
stuff=charin(afilename,1,alen)
fpp=stream(afilename,'c','close')
yaman=1
wow=replacestrg(wow,'&','&','ALL')
wow=replacestrg(stuff,'<','<','ALL')
wow=replacestrg(wow,'>','>','ALL')
wow=replacestrg(wow,'"','"','ALL')
return wow
end
when atype=1 then do /* html text, create mode */
alen=min(chars(afilename),10000)
stuff=charin(afilename,1,alen)
fpp=stream(afilename,'c','close')
stuff=space(translate(stuff,' ','00090a0d1a1b'x))
wow=look_header(afilename)
if wow<>0 then do
yaman=2
return wow
end /* Do */
if wow=0 & asummary<>2 then
return gmess.4
WOW=LOOK_HTAG() /* use <Hn> for summary */
if wow<>0 then do
yaman=1
return wow
end /* Do */
return gmess.3
end
otherwise do
say " ERROR: should not be here in make summary "
return gmess.4
end
end
/******************/
/* read a description file with possible continuation lines */
make_desc:procedure expose comment_Flag continuation_flag latestd. fdescribe
parse arg checkd
latestd.=''
foo2=checkd||fdescribe
if stream(foo2,'c','query exists')="" then do /*no such file */
checkd.0=0
return 0
end /* do */
aname='';build1=''
do forever
if lines(foo2)=0 then leave
if abbrev(strip(alin),comment_flag) then iterate /* comments */
alin=strip(linein(foo2))
if abbrev(alin,continuation_flag)=1 then do /* continuations */
build1=build1||substr(alin,length(continuation_flag)+1)
iterate
end /* else, got a file name. So write prior entry */
if aname<>'' then do
fnm=strip(translate(filespec('n',aname))) /* check the descriptions, and return match if found */
latestd.fnm=build1
end
parse var alin aname build1
end /* do */
if aname<>'' then do
fnm=strip(translate(filespec('n',aname))) /* check the descriptions, and return match if found */
latestd.fnm=build1
end
xx=stream(foo2,'c','close')
return igoo
/* ----------------------------------------------------------------------- */
/* Look for "desc" field in header */
/* ----------------------------------------------------------------------- */
look_header: procedure expose stuff url_title
parse arg afile
dowrite=0
do until stuff=""
parse var stuff p1 '<' tag '>' stuff
if translate(word(tag,1))="HEAD" then do /* now in head !*/
dowrite=1
iterate
end
if dowrite=0 then iterate /* wait till we get into head .. */
if translate(word(tag,1))="/HEAD" then /* out of head, all done ! */
leave
/* IT IS A TITLE TAG? */
if translate(word(tag,1))="TITLE" then do
parse var stuff url_title '<' footag '>' stuff
end
/* is it a META HTTP-EQUIV or a META NAME ? */
if translate(word(tag,1))="META" then do
parse var tag ameta atype '=' rest
tatype=translate(atype)
if tatype="HTTP-EQUIV" | tatype="NAME" then do
parse var rest aval1 rest
REST=STRIP(REST)
aval1=strip(aval1) ;
aval1=strip(aval1,,'"')
if abbrev(translate(aval1),'DESC')<>1 then iterate
aval2=" "
foo1=ABBREV(translate(rest),'CONTENT')
if foo1>0 then do
PARSE VAR REST FOO '=' AVAL2
aval2=strip(aval2)
aval2=strip(aval2,'b','"')
WOW=LEFT(AVAL2,500)
return WOW
end
end /* name or http-equiv */
end /* meta */
end /* stuff */
return 0
/* ----------------------------------------------------------------------- */
/* Extract <hn> fields */
/* ----------------------------------------------------------------------- */
look_htag: procedure expose stuff filename
stuff0=left(stuff,1000)
amessage=""
dowrite=0
do until stuff=""
parse var stuff p1 '<' tag '>' stuff
ttag=translate(word(tag,1))
if wordpos(ttag,' H1 H2 H3 H4 TITLE')>0 THEN DO /* grab stuff */
parse var stuff amess '<' tag2 '>' stuff
amessage=amessage||amess||'<b> | </b>'
end
end
if amessage="" then do /* getting desperate -- grab any old words! */
do until stuff0=""
parse var stuff0 p1 '<' tag '>' stuff0
amessage=amessage||' '||p1
end
end
if amessage="" then
return 0
amessage=left(amessage,300) /* keep it short */
return amessage
/***************************************************/
/* build a "description-cache index"
Call as:
status=build_desc_cache(outname,swifile)
where
outname: .dct file to create
swifile : index file built from
and
status = 1 : success, 0=failure
And where the DESC. variable is used (via an expose)
DESC. should be structured as:
desc.0 : # of records
desc.i : the identifier (as stored in the swish index file)
desc.i.!sumtype : 0= none,
1= generated
2= derived from directory-specific description file
desc.i.!title : the title (as stored in the swish index file)
desc.i.!size : the size (as stored in the swish index file)
desc.i.!summary : the summary. Might be "No Summary Available "
*/
build_desc_cache:procedure expose desc.
parse arg outname,amessage,verbose
/*
The structure is:
idstring : identifies the file type, starts with a #GOSWISH and ends with a crlf
Example: #GOSWISH 1.4 This is descriptive summaries for foo.swi
The idstring must be less then 500 characters.
parameters: A space delimited list of parameters:
NRECS: # of records,
IDBYTES: # of bytes used to score record id digests,
OFFBYTES: # of bytes used to store offset in body-of-records, and
BODYAT: # offset to first byte of body-of-records
indx: list of record-id digests and offsets.
body-of-records: the various records; with fields seperated by '05'x character
Terminator: a string consisting of crlf"END." (useful for checking integrity)
*/
idstring="#GOSWISH 1.4 : "||strip(amessage)||'0d0a'x
/* create a list of digests of each entry name */
do mm=1 to desc.0
if (mm//1000)=1 then say "Generating digest for # "mm
md5s.mm=rexx_md0(desc.mm)
end /* do */
/* check for 4 char, 8 char and 16 char uniqueness. If all
these fail, all 32 characters (16 bytes) */
iuse=2
do iss=2 to 16 by 2
iuse=iss*2 /*4,6,8,..,16 */
drop tlist.
drop idlist.
tlist.=0
iok=1 /* assume okay */
do mm=1 to desc.0
a1=left(md5s.mm,iuse) /* left most iuse characters of digest*/
if tlist.a1<>0 then do /* is this "id" already used? */
jj=tlist.a1
if desc.jj<>desc.mm then do
igg2=iuse/2
say ' repeated 'igg2 ' character id = #'a1' 'mm' 'tlist.a1
iok=0 /* yep, leave and try larger set of character */
leave
end
end /* do */
tlist.a1=mm /* mark this id as used */
idlist.mm=a1 /* save for later use */
end /* do */
if iok=1 then leave /* this size works */
end /* do */
idbytes=iuse/2 /* # hex chars /2 = # of bytes */
say "Using key length of " idbytes
/* Build the string of contents. An entry at a time.
Each entry has fields seperated by '05'x.
Each entry starts with a 2 byte size code (hence max entry size is 60k), where
the size includes seperators but NOT the two byte size code
Iats.ii points to the start of the entry (to first byte of the 2 byte size code)
*/
div5='05'x
body_of_records=''
do ii=1 to desc.0
if (ii//1000)=1 then say "...examining entry # " ii
blk0=desc.ii.!sumtype||div5||desc.ii||div5||desc.ii.!title||div5||desc.ii.!size
c2=translate(desc.ii.!summary,' ','0001020304050607'x) /* convert some stuff to ' '*/
blk0=blk0||div5||c2||div5
il=length(blk0)
if il>99999 then do
blk0=left(blk0,99999) /* should never happen, but ... */
il=99999
end
ilc=left(il,5,' ')
blk0=ilc||div5||blk0
iats.ii=length(body_of_records)+1
body_of_records=body_of_records||blk0
end
/* Create offset to the entries contained in body_of_records (use iats.)
But first-- how many bytes needed for this offset value? */
select
when length(body_of_records)<64000 then offbytes=2
when length(body_of_records)<16000000 then offbytes=3
otherwise offbytes=4
end
parameters=desc.0' 'idbytes' 'offbytes' '
/* build the index to bigblock: desc.0 items with each item consisting of
an id (with a length of idbytes bytes) and an offset (with a length of offbytes bytes)
*/
indx=''
jpt=offbytes*2
do mm=1 to desc.0
ida=x2c(strip(idlist.mm))
apt= right(d2x(iats.mm),jpt,0)
apt=x2c(apt)
indx=indx||ida||apt
end /* do */
indx=indx||'ENDINDEX'||'0d0a'x
/* we now have id string, index, and body of entries.
Compute total length of idstring + parameters + index + 10 -- add this value
to parameters (in a 8 character integer + crlf) */
isize=length(idstring)+length(parameters)+10+length(indx)+1
parameters=parameters||right(isize,8,' ')||'0d0a'x
/*
Put 'em together and write'em out */
bigblock=idstring||parameters||indx||body_of_records||'0d0a'x||'END.'
ff=sysfiledelete(outname)
sike=charout(outname,bigblock,1)
if sike<>0 then return 0
sike=stream(outname,'c','close')
return 1
/****************************************/
/* return a record, given a string (as pulled from swish index)
Requires dctindx. file (as reated by load_desc_cache) to be expose
Call as:
arecord=read_desc_record(lookfor)
where
lookfor : string to look for (should be one of the identifiers in the swish index file)
and
arecord :the record corresponding to lookfor, or a blank if no such record
Arecord can be parsed using
div='05'x
parse var arecord summary_type (div) title (div) size (div) description
where summary_type: 0= none,
1= generated,
2= derived from directory-specific description file
3= hand entered (i.e.; edit mode
*/
read_desc_record:procedure expose dctindx.
parse arg lookfor
div='05'x
md5=rexx_md0(strip(lookfor))
rr=left(x2c(md5),dctindx.!keylen)
thisoff=dctindx.rr
if thisoff=0 then return ""
off2=thisoff+dctindx.!offset
reclen=strip(charin(dctindx.!file,off2,5))
arec=charin(dctindx.!file,off2,reclen+6)
parse var arec dlen (div) summary_type (div) thename (div) thetitle (div) ,
thesize (div) thesummary (div) .
return summary_type||div||thetitle||div||thesize||div||thesummary
/****************************************/
/* load the index, and other info, from a decription-cache file
Call as:
status=load_desc_cache(dctfile)
where
dctfile : the name of the description cache file
and
status is 1 for okay, or a negative valued error code
error codes are:
-1 = "Not a GoSWISH descriptive-summaries cache file"
-2 = "File corrupted (problem with terminiator) "
-3 = Corrupted GoSWISH description-cache file (improper termination of index): "
And where
dctindx. is set (it's exposed). Note that dctindx. will be intialized.
DCTINDX. is structured as:
DCTINDX.0 = # records
DCTINDX.!KEYLEN : size (in bytes) of the "tails"
DCTINDX.!OFFSET : start (in dctfile) of first record
DCTINDX.!FILE : name of file this is derived from
DCTINDX.!MESSAGE : message stored with file
DCTINDX.atail=offset
where atail is the DCTINDX.!KEYLEN length (in bytes) x2c hash of what you want to lookup
offset is the offset (after DCTINDX.!OFFSET, of the start of this record.
******/
load_desc_cache:procedure expose dctindx.
parse arg dctfile
drop dctindx.
dctindx.=0
fsize=stream(dctfile,'c','query size')
abegin=charin(dctfile,1,min(600,fsize))
parse var abegin agoswish iver ':' amess '0d0a'x abegin
if strip(translate(agoswish))<>'#GOSWISH' then return -1
aend=charin(dctfile,fsize-3,4)
if aend<>'END.' then return -2
parse var abegin nrecs idbytes offbytes bodyat '0d0a'x .
dctindx.!message=amess
dctindx.0=nrecs
dctindx.!keylen=idbytes
dctindx.!offset=bodyat-1
dctindx.!file=dctfile
/* get the index */
iget=((idbytes+offbytes)*nrecs)
goof=charin(dctfile,1,iget+600)
parse var goof . '0d0a'x . '0d0a'x goof
goof=left(goof,iget+8)
if right(goof,8)<>'ENDINDEX' then return -3
do ii=1 to nrecs
igg=((ii-1)*(idbytes+offbytes))+1
atail=substr(goof,igg,idbytes)
dctindx.atail=c2d(substr(goof,igg+idbytes,offbytes) )
end /* do */
return 1
/* ------------- */
/* ----------------------------------------------------------------------- */
/* REPLACESTRG: In string astring, find first occurence substring target and
. replace it with substring putme
. if no target, return unchanged astring
. if no putme, then remove target
. if type=backward, then find/change LAST occurence
. if type=all, find/change all occurences
. if exactmatch=yes, then do not capitalize during search (exact match only */
/* ----------------------------------------------------------------------- */
replacestrg: procedure
exactmatch=0
backward=0 ; doall=0
parse arg astring , target , putme , type , exactmatch
type = translate(type)
if type="BACKWARD" then backward="YES"
if type="ALL" then doall="YES"
iat=1
joelen=length(target)
joelen2=length(putme)
doagain: /* here if doall=yes */
if exactmatch="YES" then do
if backward="YES" then
joe= lastpos(target,astring)
else
joe= pos(target,astring,iat)
end
else do
if backward="YES" then
joe= lastpos(translate(target),translate(astring))
else
joe= pos(translate(target),translate(astring),iat)
end
if joe=0 then
return astring
astring=delstr(astring,joe,joelen)
if putme<>' ' then
astring=insert(putme,astring,joe-1)
if doall="YES" then do
iat=joe+joelen2
signal doagain
end
/* else, all done */
return astring
/*******************************************/
/* some initializations */
initit:
/*---- load the rexxutil library */
foo=rxfuncquery('sysloadfuncs')
if foo=1 then do
call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
call SysLoadFuncs
end
ansion=checkansi()
if ansion=1 then do
aesc='1B'x
cy_ye=aesc||'[37;46;m'
normal=aesc||'[0;m'
bold=aesc||'[1;m'
re_wh=aesc||'[31;47;m'
reverse=aesc||'[7;m'
end
else do
say " Warning: Could not detect ANSI.... everything will look ugly ! "
cy_ye="" ; normal="" ; bold="" ;re_wh="" ;
reverse=""
end /* Do */
return 0
/* ------------------------------------------------------------------ */
/* function: Check if ANSI is activated */
/* */
/* call: CheckAnsi */
/* */
/* where: - */
/* */
/* returns: 1 - ANSI support detected */
/* 0 - no ANSI support available */
/* -1 - error detecting ansi */
/* */
/* note: Tested with the German and the US version of OS/2 3.0 */
/* */
/* */
CheckAnsi: PROCEDURE
thisRC = -1
trace off
/* install a local error handler */
SIGNAL ON ERROR Name InitAnsiEnd
"@ANSI 2>NUL | rxqueue 2>NUL"
thisRC = 0
do while queued() <> 0
queueLine = lineIN( "QUEUE:" )
if pos( " on.", queueLine ) <> 0 | , /* USA */
pos( " (ON).", queueLine ) <> 0 then /* GER */
thisRC = 1
end /* do while queued() <> 0 */
InitAnsiEnd:
signal off error
RETURN thisRC
/**********/
/* bogus strigin procedure */
stringin2:procedure expose bold normal desc.
parse arg amess,iff
parse var amess . '//' . '/' showmess
if length(showmess)>35 then showmess='..'||right(showmess(32)
afoo: call charout,bold showmess': 'normal
a=sysgetkey('noecho')
ia=c2d(a)
iu=''
if ia=0 then do
a=sysgetkey('noecho')
ia=c2d(a)
if ia=80 then iu=iff+1
if ia=72 then iu= iff-1
if ia=73 then iu=iff-10
if ia=81 then iu=iff+10
if iu<>'' then do
say
return max(min(iu,desc.0),1)
end
call charout,'0d'x
signal afoo
end /* do */
if a='?' | a='@' then return a
if ia=26 | ia=27 | ia=32 then do
return a
end
if a=',' | a='<' then do
say
return '<'
end
if ia=10 | ia=13 then do
say
return ''
end /* do */
call charout,a
pull a2
return a||a2
/************/
/* read file into ffread stem var */
afileread:procedure expose clines.
parse arg hfile
crlf='0d0a'x
if stream(hfile,'c','query exists')="" then return 0
tmp=strip(charin(hfile,1,chars(hfile)),'t','1a'x)
tt=stream(hfile,'c','close')
itmp=0
do until tmp=""
itmp=itmp+1
parse var tmp clines.itmp (crlf) tmp
end /* do */
clines.0=itmp
return itmp
/* See if directory exists , 0=no 1=yes*/
dir_exists:procedure
parse upper arg lookfor
lookfor=strip(lookfor,'t','\')
adrive=filespec('d',lookfor) /* does drive exist? */
if adrive<>"" then do
oo2=sysdrivemap(,'used')
if pos(translate(adrive),translate(oo2))=0 then return 0 /* no such drive */
end
eek=lastpos('\',lookfor)
if eek>0 then do
lookfor1=substr(lookfor,eek+1)
foo=delstr(lookfor,eek)
end
else do
return 1 /* it's a root dir */
end /* do */
foo=foo'\*.*'
aa=sysfiletree(foo,'eek','DO')
do mm=1 to eek.0
if translate(filespec('n',eek.mm))=lookfor1 then do
return 1
end /* do */
end /* do */
return 0
/******/
show_entries:procedure expose desc. bold normal reverse
parse arg iat
iat=max(min(iat,desc.0),1)
mm0=0
do forever
if length(desc.iat)+length(desc.iat.!title)>65 then do
mm0=mm0+2
say bold iat normal reverse strip(translate(desc.iat)) normal bold ' :: '
say copies(' ',15) normal left(desc.iat.!title,62)
end
else do
say bold iat normal reverse strip(translate(desc.iat)) normal bold ' :: ' normal desc.iat.!title
mm0=mm0+1
end
if mm0>20 then return iat
iat=iat+1
if iat>desc.0 then return iat
end /* Do */
/***************************************************/
/* a hash, based on md5 */
rexx_md0:procedure
parse arg stuff
numeric digits 11
lenstuff=length(stuff)
c0=d2c(0)
c1=d2c(128)
c1a=d2c(255)
c1111=c1a||c1a||c1a||c1a
slen=length(stuff)*8
slen512=slen//512
/* pad message to multiple of 512 bits. Last 2 words are 64 bit # bits in message*/
if slen512=448 then addme=512
if slen512<448 then addme=448-slen512
if slen512>448 then addme=960-slen512
addwords=addme/8
apad=c1||copies(c0,addwords-1)
xlen=reverse(right(d2c(lenstuff*8),4,c0))||c0||c0||c0||c0 /* 2**32 max bytes in message */
/* NEWSTUFF is the message to be md5'ed */
newstuff=stuff||apad||xlen
/* starting values of registers */
a ='67452301'x;
b ='efcdab89'x;
c ='98badcfe'x;
d ='10325476'x;
lennews=length(newstuff)/4
/* loop through entire message */
do i1 = 0 to ((lennews/16)-1)
i16=i1*64
do j=1 to 16
j4=((j-1)*4)+1
jj=i16+j4
m.j=reverse(substr(newstuff,jj,4))
end /* do */
/* transform this block of 16 chars to 4 values. Save prior values first */
aa=a;bb=b;cc=c;dd=d
/* do 4 rounds, 16 operations per round (rounds differ in bit'ing functions */
S11=7
S12=12
S13=17
S14=22
a=round1( a, b, c, d, 0 , S11, 3614090360); /* 1 */
d=round1( d, a, b, c, 1 , S12, 3905402710); /* 2 */
c=round1( c, d, a, b, 2 , S13, 606105819); /* 3 */
b=round1( b, c, d, a, 3 , S14, 3250441966); /* 4 */
a=round1( a, b, c, d, 4 , S11, 4118548399); /* 5 */
d=round1( d, a, b, c, 5 , S12, 1200080426); /* 6 */
c=round1( c, d, a, b, 6 , S13, 2821735955); /* 7 */
b=round1( b, c, d, a, 7 , S14, 4249261313); /* 8 */
a=round1( a, b, c, d, 8 , S11, 1770035416); /* 9 */
d=round1( d, a, b, c, 9 , S12, 2336552879); /* 10 */
c=round1( c, d, a, b, 10 , S13, 4294925233); /* 11 */
b=round1( b, c, d, a, 11 , S14, 2304563134); /* 12 */
a=round1( a, b, c, d, 12 , S11, 1804603682); /* 13 */
d=round1( d, a, b, c, 13 , S12, 4254626195); /* 14 */
c=round1( c, d, a, b, 14 , S13, 2792965006); /* 15 */
b=round1( b, c, d, a, 15 , S14, 1236535329); /* 16 */
a=m32add(aa,a) ; b=m32add(bb,b) ; c=m32add(cc,c) ; d=m32add(dd,d)
end
aa=c2x(reverse(a))||c2x(reverse(b))||c2x(reverse(C))||c2x(reverse(D))
return aa
c=round1( c, d, a, b, 10 , S13, 4294925233); /* 11 */
b=round1( b, c, d, a, 11 , S14, 2304563134); /* 12 */
a=round1( a, b, c, d, 12 , S11, 1804603682); /* 13 */
d=round1( d, a, b, c, 13 , S12, 4254626195); /* 14 */
c=round1( c, d, a, b, 14 , S13, 2792965006); /* 15 */
b=round1( b, c, d, a, 15 , S14, 1236535329); /* 16 */
/* round 1 to 4 functins */
round1:procedure expose m. c1111 c0 c1
parse arg a1,b1,c1,d1,kth,shift,sini
kth=kth+1
t1=c2d(a1)+c2d(f(b1,c1,d1))+ c2d(m.kth) + sini
t1a=right(d2c(t1),4,c0)
t2=rotleft(t1a,shift)
t3=m32add(t2,b1)
return t3
/* add to "char" numbers, modulo 2**32, return as char */
m32add:procedure expose c0 c1 c1111
parse arg v1,v2
t1=c2d(v1)+c2d(v2)
t2=d2c(t1)
t3=right(t2,4,c0)
return t3
/*********** Basic functions */
/* F(x, y, z) == (((x) & (y)) | ((~x) & (z))) */
f:procedure expose c0 c1 c1111
parse arg x,y,z
t1=bitand(x,y)
notx=bitxor(x,c1111)
t2=bitand(notx,z)
return bitor(t1,t2)
/* G(x, y, z) == (((x) & (z)) | ((y) & (~z)))*/
g:procedure expose c0 c1 c1111
parse arg x,y,z
t1=bitand(x,z)
notz=bitxor(z,c1111)
t2=bitand(y,notz)
return bitor(t1,t2)
/* H(x, y, z) == ((x) ^ (y) ^ (z)) */
h:procedure expose c0 c1 c1111
parse arg x,y,z
t1=bitxor(x,y)
return bitxor(t1,z)
/* I(x, y, z) == ((y) ^ ((x) | (~z))) */
i:procedure expose c0 c1 c1111
parse arg x,y,z
notz=bitxor(z,c1111)
t2=bitor(x,notz)
return bitxor(y,t2)
/* bit rotate to the left by s positions */
rotleft:procedure
parse arg achar,s
if s=0 then return achar
bits=x2b(c2x(achar))
lb=length(bits)
t1=left(bits,s)
t2=bits||t1
yib=right(t2,lb)
return x2c(b2x(yib))