User:Don Guinn/AddHelpLinks.ijs

From J Wiki
Jump to: navigation, search
0 : 0

Runs under version: J602.

Right now to run: It runs when loaded.  It does pop up windows before
it actually does things.

Fixed handling "<a href"s in debugs.htm 7/23/2003.

General Idea -

Want to be able to find multiple occurances of a name in help.
Presently the Index only gives a link to files in which the name
occurs.  To see the name in the file requires an additional search.
Then, to see others, it is necessary to go back to the Index to find
the next file in which it occurs.  Secondly, it is difficult to follow
trails on different names as they may or may not be indexed.

This searches out the occurances of the names found in the Index and
add links to its first occurance in the file.  Within a file each
occurance contains a link to the next occurance in the file and the
last back to the name in the Index.

In addition, all indexed words are highlighted in the files so it is
obvious that they are also indexed and one can go directly to another
keyword to search for additional information.

The general processing consists of manipulating a rank 2 array where
each row in the array describes a link found in the index.  This array
will be reordered and reboxed into various configurations as
processing proceeds.  This information is kept in the noun "links"
and its row contents are described later.

INDEX FILE CHANGES

The internally assigned name for the first occurance of the name in
the target file (linkstart) is added to each href file name in the
Index file.  For now the "a name"s in the index files are used to
link back to the proper place in the Index files.  This may need
changing if browsers can`t handle them.  If that`s the case the
indices to the names is saved for adding a better name.

TARGET FILE CHANGES

Each occurance of the referenced word in the target file is modified
by adding a name using the linkto value and the string 'Mn', where
"n" is the nth occurance of the referenced word in the file.  Also,
a link (href) is added to the next occurance of the word in the file,
or, for the last occurance, back to the point in the index file where
the word is found (a name in the index file) .

For example, coinsert and its reference to relhigh.htm in c.htm the
links should look like (Separated into multiple lines for reading) :

  The link to a file in the index file c.htm:
    <a name="coinsert"</a><a href="../user/relhigh.htm#L12M0">
    J 5.01 Release Highlights and Overview</a>
  This is the 12th (zero origin) unique name referenced in relhigh.htm
  and the a name for coinsert is already in the index file.

  The first target in the file relhigh.htm:
    <a name="L12M0"></a><a href="L12M1">coinsert</a>
  This replaces the word "coinsert" in the file.

  The next (last) target:
    <a name="L12M1"</a><a href="..\index\c.htm#coinsert">coinsert</a>
  This uses the name already in the index file.  Microsoft Explorer
  appears to be case insensitive.  This causes a link to the wrong
  place for names like "e." and "E.".

For now this will attempt to use the name tags already in the index.
If this doesn`t work an internally built name will be used for the
link back to the index file.  It would look like:

  The link to a file in the index file c.htm:
    <a name="coinsert"</a>
    <a name="B57"</a><a href="../user/relhigh.htm#L12M0">
    J 5.01 Release Highlights and Overview</a>
  This is the 12th (zero origin) unique name referenced in relhigh.htm
  and is the 57th (zero origin) link in c.htm.  The "a name" for
  coinsert would be left alone.

  The first target in the file relhigh.htm:
    <a name="L12M0"></a><a href="L12M1">coinsert</a>
  This replaces the word "coinsert" in the file.

  The next target:
    <a name="L12M1"</a><a href="..\index\c.htm#B57">coinsert</a>
  Assuming this is the last reference for coinsert in relhigh.htm it
  links back to the index.  The link back to the dictionary assumes
  that all index links are in directories in the same directory
  as the index directory.

There are several links in the index to files which in fact do not
contain the word.  In Netscape if an xref link is to a nonexisting
internal name reference then it is ignored and displays at the
beginning of the file.  Unfortunatly Explorer positions at the bottom
of the file.  An example of this is the word a. of which there are no
occurances of a. in relhigh.htm.  I think that JSoftware used the key
'a.' instead of 'a/.' in a regular expression.  To avoid confusion,
when the name is missing the link name is inserted at the beginning of
the file.

The steps to build these links are as follows.  The * indicates that
the step is done.

*1.  Build list of indexed phrases including containing file names and
     href files.

     Searches the Index files for names that are indexed and build
     items, each item containing the name, file where found, the file
     to which it links and the indices to the aname and the ahref
     tags in the index file.  These would be used to insert hrefs
     and possibly anames if necessary in step 5.

*2.  Group into files containing links.

     This is a simple step only to regroup the items for step 3.
     Items are put into boxes by target file for processing by target
     file.

*3.  Assign link names within each file.  The names are of the form
     Lnnn and start with L0 incrementing for each referenced name.

     Since different names can occur in a file unique link names must
     be created for the first occurance of each name in the file.
     This name is used for linking from the Index to this first
     occurance.

*4.  Rebuild each file including targets.

     This step is rather difficult as names in the Index can be
     followed with (s) indicating the name can be either singular or
     plural in the target files.  In that case the name "abc(s)" may
     appear as "abc", "abcs" or "abces" etc..

     The link name is extended to the form LnnnMmmm where mmm is the
     number for multiple occurances of name within the file.

     The link descripters have been boxed into target files from
     above.  Each box is processed to create a new version of the
     target file containing additional links.  These links serve to
     go directly to the linked name instead of the first of the file
     and also link to the next occurance of the name in the file.
     Also, defining names as a links results in highlighting them
     providing easy links for other names.

*5.  Rebuild index files to include links.

     The descripters are boxed to index file keys then each box is
     processed.  Each index file is modified adding the name pointing
     to the target name in the target file to the link file name.
     This makes the link go to the name instead of the beginning of
     the file.

*6.  Replace the files with modified versions.  Nothing is written
     until this step.  If any errors occur previously the help files
     are unaltered.

The current directory is set to the help directory to simplify reading
files.

This should do it.

Example HTML Link Tags for reference:
Within a file :
  The link :
    <A NAME=short> <H3>Short Displayed Text</H3></A>
  The target :
    <A HREF="#short>Short Displayed Text</A>
To another file :
    <A HREF="http://www.jsoftware.com">J Software Home Page</A>
To a name in another file :
  The link :
    <A HREF="This is text.htm#More">This is text.htm - More</A>
  The target (in file "This is text.htm") :
    <A NAME="More"></A>

Initially regular expressions were used for searches.  They turned out
to be far too slow.  However, the following describes what the
searches looked like.

Example regular expression search string:
  [[:cntrl:][:punct:][:space:]](x|xs|xes)[[:cntrl:][:punct:][:space:]]
    where x is the string to find.

The checks before and after the string are attempting to make sure
that the found string is a word.  The parens around the word to be
found cause the regular expression processing to return an index of
just the found word as well as the full string found.  If the word
found in the Index has "(s)" on the end then the word may be singular
or plural.  In that case the "(s)" is stripped and then expanded to
its singular and plural forms for the search.

Possible plurals:
  xxxx(s) -> xxxxs, xxxxes
  xxxy(s) -> xxxys, xxxies
  xxxe(s) -> xxxes
  xxxs(s) -> xxxses

Also need to check for names ending in "." and add a "\" in front of
the ".".

Problems with this:

  This will miss words at the beginning or end of the file.  This
  should not happen.

  Second occurances of the word separated by only one space will be
  missed.  This is probably just as well.

  Determining the plural form of a word could get sticky.  Probably
  good enough for now.

  Gave up on this approach as regular expression searches are way too
  slow.

GLOBAL NAMES:

helpdir      - path to help files.
helpindex    - path to directory containing index files.
aname        - text defining a name that is linked.
ahref        - text defining a link.
enda         - text defining the end of a link.
indexfiles   - the file names of the index files.
links        - 5 columns:
           0 - Name of index file.
           1 - Displayed string.
           2 - a pair of numbers, the first representing the index to
               the aname and the second to the ahref.  The first number
               is not used right now.  It is saved if an additional
               aname needs to be inserted in the Index files.
           3 - Name of href file.
           4 - (Added in Step 3) Unique names for each linked to file.
               This name can be used as the name to the first reference
               to the indexed name in the linked to file.  This link
               name is of the form Lnnn in links and understood to be
               extended to LnnnM0 for accessing the first occurance of
               name in the target file.
             links will be boxed into various arrangements as
             processing proceeds.
newfiles     - A boxed list, each item containing an updated version of
               a help file.
newfilenames - A boxed list of filenames corresponding to the file
               updates in newfiles.


Problems:

(Fixed) Need to put link to first instance (linkto) into the index.

Netscape checks the case of a link name (after the # sign) but
Explorer does not.  Therefore, linking back to A. goes to a. instead
of A. in the index.

A. is a mess!  The Dictionary has links to A. but they are to titles
for the A. topic in an outline, not the A. primitive.

Looks like a lot of links are eroneous.

If a #link name is not found in the href file Netscape positions the
window at the top of the file where Explorer positions at the bottom.
This is gotten around by setting the tag to be put at the top of the
file as a dummy.  It doesn`t go all the way to the top, but close.

Fixed: 7/23/2003 <a href> defined in ahref will be missed if
capatilized or extra spacesbetween "a" and "href".  Messes up debug
help.
  Need to fix:
    read_index    Unnecessary to fix as of J502a
    drop_in_links Fixed.
)

require 'files'
require 'regex'

NB. Definitions
3 : 0 ''
current_dir=: 1!:43''  NB. Save to restore later.
helpdir=: jpath '~system\extras\help\'
if. 0=#fdir helpdir do.
  helpdir=:jpath '~help\'  NB.j602
end.
indexdir=: 'index\'
1!:44 helpindex=: helpdir,indexdir NB. Make Index directory current.
aname=: '<a name="'
ahref=: '<a href="'
enda=: '</a>'
wordsep=: '[[:cntrl:][:punct:][:space:]]' NB. Reg exp word separator.
)

NB.*testdelim, testdelimlc - Test for word delimiter.
NB. Arguments:
NB.   y - text string to check.
NB.   x - indices into the text string.
NB. Return:
NB.   True  - characters are delimiters.
NB.   False - Characters are not.
NB. Tests are for non-alphanumeric.  testdelimlc checks for only
NB. lower-case characters.
xx=. a.{~((a.i.'A')+i.26),((a.i.'a')+i.26),((a.i.'0')+i.10)
testdelim=: [:-.e.&xx
xx=. a.{~((a.i.'a')+i.26),((a.i.'0')+i.10)
testdelimlc=: [:-.e.&xx

NB. Plural definitions.
NB.*cpl? - Count characters matching plural suffix.
NB. Arguments:
NB.   y - The text to search
NB.   x - The indices within y to check.
NB. Return:
NB.   A list of counts of leading matching characters.
NB. Only the count is needed.  The actual values of the words is
NB. captured by rxcut.
c=. ,!.(0{a.) NB. Catinate with null fill.  Null never equal.
NB. Possible plural suffixes for words ending in ? .
ple=. ,:,'s'
plo=. 'es' c ,: ,'s'
pls=. ,:'es'
plx=. 'exs ' c 'ex  ' c 'ices' ,:'exes' NB. Drop last 2 characters.
ply=. 'ies' c 'ys' c ,:,'y' NB. Drop last character in search.
dcpl=. 1 : 0
c=. i.{:$m
ndx=. ([+/c"_){]
([:>./0:i."1~m"_ ="1/ndx)f.
)
NB. The counting verbs.
cple=: ple dcpl
cplo=: plo dcpl
cpls=: pls dcpl
cplx=: plx dcpl
cply=: ply dcpl

NB. Code supporting Step 1. _________________________________________

NB.*read_index - Extract links from an index file.
NB. Called in Step 1.
NB. Argument:
NB.   y - Name of file to read.
NB. Return:
NB.   A boxed rank 2 array of links found in the file.  Each item
NB.   represents a link and each item contains the columns 0-3 given
NB.   in links described above.
NB.
NB. Need to save indices to insertion points for tags.  Need to put
NB. them later after they are assigned names.  Need points for adding
NB. href # extentions after existing file names so will go to name in
NB. the target file and not the first, and need the points for the
NB. existing names in the index if decided later to insert my own
NB. names due to other problems.
read_index=: (3 : 0)"0
NB. group - Get groups from y starting with x
group=. E.<;.1]
NB. get_val - Get the value after a name.
get_val=. 4 : '(y.i.''"''){.y=.(#x)}.y'

txt=. fread y
inames=. aname&get_val&.>xx=. aname group txt    NB. Separate by names.
ihref=. ahref&get_val&.>&.>ahref&group&.>xx     NB. Get links.
<y,.;,.('B' addlinknames inames),"1 0&.>ihref
)
read_index=: (3 : 0)"0
NB. get_val - Get the value after a name.
get_val=. [:{.('"'"_=])<;._1]

hcount=. 21+'<a href="z.htm">Z</a>'((E.i.1:))txt=. fread y
txt=. '<a href="a.htm">A</a>'((E.i:1:){.])hcount}.txt
ni=. nm#i.#nm=. aname E. txt
li=. lm#i.#lm=. ahref E. txt
c=. +/"1</\&.|.ni</li
inames=. get_val&>nm<;.1 txt    NB. Separate by names.
ihref=. get_val&>lm<;.1 txt    NB. Get links.
<y,.(c#inames),.(<"1 hcount+(c#ni),.li),.ihref
)

NB.*build_tag_indices - Build the indices for tags in an index file.
NB. Arguments:
NB.   y - Index list for href tags.
NB.   x - Index list for aname tags.
NB. Return:
NB.   A table of aname and corresponding href indices.
NB.     col 0 - aname indices
NB.     col 1 - corresponding href indices.
NB. These indices are used in step 6 to insert additional name
NB. information in the index files.  It cannot be done in step 1 as
NB. the target files must be processed before the names to insert are
NB. built.
build_tag_indices=: 4 : 0
c=. +/"1</\&.|.x</y
(c#x),.((#y)-+/c)}.y
)

NB. Code supporting step 3. _________________________________________

NB.*addlinknames - Put a link name after the name.
NB. Called in Step 3.
NB. Arguments:
NB.   y - a list of boxed names.
NB.   x - a single character to prefix each link.
NB. Return:
NB.   A boxed list of boxes, each box containing the boxed name and
NB.   the boxed link.
addlinknames=: 4 : '<"1 y,.x,&.>":&.>"0 i.#y'

NB. Code supporting Step 4. ________________________________________

NB.*add_targets - Read a file and insert link targets.
NB. Called in Step 4.
NB. Argument:
NB.   y - A list from links grouped by target link file name.
NB.        ifile     - For link back to the index file used in last
NB.                    occurance of an instance of name.
NB.        keys      - The strings to find in y .
NB.        linkback  - (Changed.  See description in link).
NB.        file      - The name of the target file being processed.
NB.                    All instances of file should be the same.
NB.        linkstart - Tag to use with the first instances of name in
NB.                    file.
NB. Return:
NB.   The file with the destination names tagged and links to next
NB.   names within the file and the last name linked back to the
NB.   index.  Any names already in a link are not tagged again.
NB. Global:
NB.   file - For use in split message box, if error.
NB.
NB. Writes to execution window a log of each file modified so user
NB. knows something is happening.
NB.
NB. There should be only one file name in f below.
add_targets=: 3 : 0
'ikll f'=. |:0 0 0 1 0</."1 yyy=: y
assert. 1=#f=. ~.f
if. _1={.filetxt=. ,fread file=: {.,f do.
  write_error '"Read Error.  add_targets cannot read ',(,":>file),'."'
end.
'txthdr txt txtfoot'=. split filetxt
targets=. (1{"1 ikll)find_targets&.><txt
targets=. targets drop_in_links tolower txt
t1=. targets build_tags ikll
targets=. targets{~order=. /:targets=. ;targets
t1=. order{;t1
t=. _2,\targets rxcut txt
t2=. (<'>'),&.>(}:}."1 t),&.><'</a>'
txt=. ;({."1 t),.(,.t1,a:),.t2,a:
newtargets=: newtargets+#targets
log 'names found ',(5":#y),'  links added ',(5":#targets),'  ',;file
txthdr,txt,txtfoot
)

NB.*build_tags - Build the html tags to go around the keyword.
NB. Arguments:
NB.   y - an item (row) from ikll in add_targets.
NB.   x - an item (boxed) from targets in add_targets.
NB. Return:
NB.   a boxed list of the html to preceed the keyword.
NB.
NB. Must watch out for case where x is null.
build_tags=: 4 : 0"0 1
'ifile keys linkback linkstart'=. y
NB. tags=.<'..\',indexdir,ifile,'#',linkback
tags=. <'..\',indexdir,ifile,'#',keys
tname=. (<linkstart),&.>'M',&.>":&.><"0 i.count=. #>x
thref=. (-count){.('#',&.>tname),tags
<([:<;)"1(<aname),.tname,.(<'"',enda,ahref),.thref,.<'"'
)

NB.*drop_in_links - Drop any words already in a link.
NB. Arguments:
NB.   y - Text from the html to search.
NB.   x - A boxed list of start/length items for words found.
NB. Return:
NB.   The boxed list x except any names within links are dropped.
NB.
NB. The indices of html reference links and corresponding ends (r)
NB. text are compared to the list of indices to words to link found
NB. in the in the text.  The indices to any words already within a
NB. link are dropped.  Only the start of a word is checked.  The end
NB. is not.
NB.
NB. HTML is case insensitive and whitespace may be variable.  As a
NB. result this routine is extended to ignore case and for whitespace
NB. to be multiple blanks or whatever.  Therefore text is converted
NB. to lowercase and line feeds replaced with blanks for the purpose
NB. of locating HTML commands.  Along with this, HTML does not seem
NB. to allow whitespace within commands unless specifically noted in
NB. the command definition.  Therefore, the command recognition is
NB. done both with specific concern for whitespace and partially
NB. ignoring whitespace.
NB.
NB. This should eventually extended to a complete and proper treatment
NB. of HTML but this should be sufficient for the time being.
drop_in_links=: 4 : 0
txtb=. ;:txt=. tolcwsp y
f=. E.#[:i.[:#]
NB. Find all boxed "<"s & mark those which are also ahrefs.
s=. (txtb E.~;:'<')#txtb E.~;:'<a href='
NB. Get indices of unboxed ahrefs.
start=. s#'<' f txt
NB. Double check those selected for "<a " at the start.
NB. No whitespace is allowed between the "<" and the "a".
start=. start#~start e. '<a' f txt
NB. Find ends of ahrefs.
end=. enda f txt
NB. Remove any references already in an ahref.
r=. start,:(+/"1 start>/end){end
masks=. (<r)([:=/[:=/</)&.>{."1&.>x
masks#&.>x
)

NB. tolcwsp - Like tolower but also converts whitespace to blanks.
NB. Also converts periods, colons and quotes to blanks so "<"s will
NB. always be treated as "<"s when boxed and boxing will not get
NB. messed up by being within quotes.  This should not hurt as
NB. txt is used mostly for determining the indices to the "<"s.
'l u'=. (a.i.'aA') +each <i.26
bl=. a.i.' '{.~#wsp=. a.i.LF,CR,TAB,'.:'''
tolcwsp=: a.&i. { (((l,bl){a.) (u,wsp)} a.)"_

NB.*find_targets - Find indices to a string.
NB. Called in step 4 from add_targets.
NB. Arguments:
NB.   y - string to search
NB.   x - key to find.
NB.        A key can have "(s)" stuck on the end.  If so then it is
NB.        necessary to check for plural form as well.
NB.        If key ends in ".' or ":" search txt, otherwise txtlc.
NB. Return:
NB.   a 2-column list containing:
NB.     col 0 - the index where string is found
NB.     col 1 - the length of the string
NB.
NB. If the string ends in "(s)" possible plurals are added to the
NB. search.
NB.
NB. Tried to use regular expressions to search but they are far too
NB. slow.
NB.
NB. Really need to check to make sure l > 0 for x& y cases, but it
NB. doesn`t seem to be a problem at this time.
find_targets=: 4 : 0
if. '.:'e.~{:;x
do. NB. Trailing word separator is not needed for this case.
  start=. x(E.#[:i.[:#])y
  start=. start#~testdelim y{~<:start
  r=. (start#~-.'.:'e.~y{~start+#x),.#x NB. Not another name?
elseif. '(s)'-:_3{.x do. NB. Set pattern if plural.
  x=. tolower _3}.x
  y=. tolower y
  start=. x(E.#[:i.[:#])y
  start=. start#~testdelimlc y{~<:start
  select. {:x
  case. 's' do. sl=. (start+l=. #x)cpls y
  case. 'e' do. sl=. (start+l=. #x)cple y
  case. 'x' do. sl=. (start+l=. _2+#x)cplx y
  case. 'y' do. sl=. (start+l=. <:#x)cply y
  case. do. sl=. (start+l=. #x)cplo y
NB. What about singular ending in 'is' like "axis"?
NB. Not going to worry about Latin "um" to "a".
  end.
  mm=. testdelimlc (start+len=. l+sl){y
  r=. mm#start,.len
elseif. do.
  x=. tolower x
  y=. tolower y
  start=. x(E.#[:i.[:#])y
  start=. start#~testdelimlc y{~<:start
  r=. (start#~testdelimlc y{~start+#x),.#x
end.
if. 0=#r do. ,:0 0 end. NB. So MS Explorer will go to top of file.
)


NB.*split - Split up help file into header, body and trailer.
NB. Argument:
NB.   y - The text of a help file.
NB. Return:
NB.   Three boxed text strings: header, body, footer.
NB.
NB. A test is made to make sure that three strings are returned.
NB. If not an error message box is popped up.
NB.
NB. Right now if no header and footer this gives an error.  May want
NB. to just return null for a missing header or trailer if it`s ok
NB. for them to be missing in some circumstances.
split=: 3 : 0
sep=. '<!--top jump end-->';'<!--bottom jump start-->'
r=. (1,}.+./(E.&y)&>sep)<;.1 y
if. 3~:#r do.
NB. t=.'"Error in add_targets.  Missing header or footer in '
NB. write_error t,(;file),'."'
  mm=. '"Missing Header or Footer in ',(;file),'.',LF,LF
  mm=. mm,'You may stop now or continue processing.',LF
  mm=. mm,'In either case no files will be rewriten yet.',LF
  mm=. mm,'You will be prompted before the files are to be written.'
  mm=. mm,LF,LF,'Do you wish to continue?" '
  mm=. mm,'mb_yesno mb_iconasterisk'
  if. 'NO'-:wdmb mm
  do. 13!:8]3
  else. NB. Split by start and end body.
    sep=. '<body ';'</body>'
    r=. (1,}.+./(E.&y)&>sep)<;.1 y
  end.
end.
)

NB. Code Supporting Step 5 _________________________________________

NB.*add_index - Add #names to index file links.
NB. Argument:
NB.   y - Links grouped by index file name.
NB. Return:
NB.   The contents of the index file with #names added.
add_index=: 3 : 0
'f keys i phrases links'=. <"1|:y/:(2{"1 y)
if. _1={.txt=. ,fread file=: ~.,f do.
  write_error '"Read Error.  add_index cannot read ',(,":>file),'."'
end.
'inames ihrefs'=. |:>i
newtargets=: newtargets+#ihrefs
t=. _2,\((ihrefs+#ahref),.#&>phrases) rxcut txt
;t,.('#',&.>links,&.><'M0'),a:
)


NB. Utility code. __________________________________________________

NB.*rxapplyic - Find specified strings ignoring case & apply the verb.
NB. Copied from rxapply in regex.ijs and modified to ignore case.
NB. Arguments:
NB.   y - string to search.
NB.   x - regular expression used for search.
NB.   u - verb to apply to each found string.
NB. Return:
NB.   y with each occurrance of the found string replaced from the
NB.   results of applying u to each.
NB.
NB. This is accomplished by converting x and y to lower case before
NB. passing them to rxmatches.
rxapplyic=: 1 : 0
:
if. L. x do. 'pat ndx'=. x else. pat=. x [ ndx=. ,0 end.
if. 1 ~: #$ ndx do. 13!:8[3 end.
mat=. ({.ndx) {"2 pat rxmatches&tolower y
r=. u&.> mat rxfrom y
r mat rxmerge y
)

NB.*write_error - Write out an error message.
NB. Input:
NB.   y - Error message to display.  This should be the second double
NB.        quote delimited strings to use in wd/mb.
NB. Return:
NB.   none - right now it just terminates the run with an error.
NB.May want this to just log the error and return.
write_error=: 3 : 0
wdmb y,' mb_iconstop'
13!:8]3
)

log=: 13 : 'y (1!:2)2'

wdmb=: 3 : 0
if. #y do.
  log y
  wd 'mb "Add Help Links" ',y
end.
)

NB. Execution starts here. __________________________________________

3 : 0 ''

mm=. '"Press OK to build links in help files.',LF,LF
mm=. mm,'You will be asked after the updates have been built as to '
mm=. mm,'whether you want the updates to be applied." '
mm=. mm,'mb_okcancel mb_iconquestion'
if.'CANCEL'-:wdmb mm do. return. end.


NB. Step 1.  Build list of indexed phrases.
log 'Reading and scanning index files.'
indexfiles=: {."1 fdir helpindex,'*.htm'
if. 0=#indexfiles do.
  wd 'mb "Error" "Help directory ',helpdir,' not found."'
  return.
end.
links=: ;,.read_index indexfiles         NB. Get links from all indices.
links=: (-.indexfiles e.~3{"1 links)#links NB. Drop index->index links.
links=: (-.((<'../index/'),&.>indexfiles) e.~3{"1 links)#links
links=: (-.'#'e.&>3{"1 links)#links NB. Drop any file names with `#`.

NB. Make sure no duplicates in a link file.
wdmb '"Problem.  Links not unique."'#~(#links)~:#~.}."1 links

NB. Step 2.  Group into files containing links.
log 'Assigning link names.'
links=: ({:"1 links)</.links

NB. Step 3.  Assign link names within each file.
links=: >L:2 'L' addlinknames&.>links
NB. Picked up an extra box.  Oh well!  Got rid of it.
NB. links=:links,.&.>l

NB. Step 4.  Rebuild each file including targets.
newtargets=: 0
newfiles=: add_targets &.>links
newfilenames=: (3&{@{.)&>links

NB. Step 5.  Rebuild index files with extended links & targets back.
if. 0=newtargets do.  NB. Quit if no target files changed.
  mm=. '"No Update Necessary.  No new references were found."'
  wdmb mm,' mb_iconexclamation'
  return.
end.
links=: ({."1</.]);links NB. Group links back by index file.
newfiles=: newfiles,add_index&.>links
newfilenames=: newfilenames,(0&{@{.)&>links


NB. Step 6.  Ready to write updated html files back.
mm=. '"Updates Complete.',LF
mm=. mm,(":newtargets),' references added successfully in '
mm=. mm,(":#newfiles),' files.',LF,LF
mm=. mm,'Do you wish to write these changes to disk?" '
mm=. mm,'mb_yesno mb_iconquestion'
if. 'NO'-:wdmb mm do. return. end.

NB. Write them.
log 'Writing Files.'
writefile=. 4 : ('NB. log y';'x fwrite y')
newfiles writefile &.>newfilenames

wdmb '"Done."'
log 'Done'
)

NB. Testing ____________________________________________
0 : 0
l=:>{.links
new=:add_targets l
new fwrite jpath '~temp\tst2.htm'
)

testtxt=: 0 : 0
<html><head><title></title><meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1"></head><body>Top<br>
<!--top jump end--><br>
This has a. in it and it is embedded here ba
another <a href="#Bottom">a. embedded</a> in a link. <br>
Mess with coinsert, coinserts 
Only first should be found.<br>
Now here is a second coinsert.<br>
Tough one. assignment<br>
Assignments should be found too.<br>
Just checking alternate assignmentes not assignmentess.<br>
And finally assignment(s)<br>
Not this one aa. or this one a..<br>
a.. should link here a.<br>
<br><br><br><br><br><br><br><br><br><br><br>
<!--bottom jump start--><br><a name="Bottom"></a>
Bottom<br>
</body></html>
)
test=: 3 : 0
helpdir=: jpath '~temp\'
indexdir=: ''
1!:44 helpindex=: helpdir,indexdir NB. Make Index directory current.
l=: 'a.htm';'a.';'B0';'tst1.htm';'L0'
l=: l,:'a.htm';'assignment(s)';'B102';'tst1.htm';'L5'
l=: l,'c.htm';'coinsert';'B57';'tst1.htm';'L12'
testtxt fwrite 'tst1.htm'
)