home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3559 < prev    next >
Internet Message Format  |  1991-06-28  |  13KB

  1. From: morgan@ms.uky.edu (Wes Morgan)
  2. Newsgroups: bit.listserv.infonets,bit.listserv.rexxlist,alt.sources
  3. Subject: Tools for determining BITNET paths  (source code included)
  4. Message-ID: <1991Jun27.155006.29927@ms.uky.edu>
  5. Date: 27 Jun 1991 15:50:06 GMT
  6.  
  7.  
  8. Occasionally, I find that I need to know the path between
  9. two BITNET nodes.  I developed the tools included below to per-
  10. form this task.
  11.  
  12. Both the REXX and Unix versions of this program require the
  13. BITNET LINKS file, which is available from LISTSERV@BITNIC.
  14. I have tested these programs using the most recent copy of
  15. BITNET LINKS; if you've made any local changes to BITNET
  16. LINKS (or its format), you're on your own.
  17.  
  18. I can't take full credit for the REXX version; it was sent
  19. to me (in a very rough form) several years ago.  I merely
  20. cleaned up the code, added the descriptive output, and
  21. added comments.  The Unix script, however, is all mine.
  22.  
  23. The REXX routine was tested under CMS Rel 5.  The Unix script
  24. was tested under AT&T System V Release 3.2.3.  If you're run-
  25. ning another operating system, you may need to alter the code.
  26. I only request that you clearly mark your changes before passing
  27. the code to other users; I don't want to receive questions about
  28. code I didn't write!  8)
  29.  
  30. Comments/questions/suggestions/flames can be directed to me at
  31. any of the email addresses at the end of this posting.
  32.  
  33. Having said all that, here's the code:
  34.  
  35. ------------------begin REXX code------------------------
  36. /************************************************/
  37. /* NODE EXEC - find and list path between nodes */
  38. /*                                              */
  39. /* Syntax NODE node1 node2                      */
  40. /*     or NODE node2  <home node is default>    */
  41. /*                                              */
  42. /* Original Author : Unknown                    */
  43. /* Version 2 by: Wes Morgan                     */
  44. /*                morgan@engr.uky.edu           */
  45. /*                                              */
  46. /* Summary of revisions                         */
  47. /*    Date       by      Comments               */
  48. /*    ????     Unknown   Original code. Several */
  49. /*                       versions on BITNET.    */
  50. /*    8804       WM      Cleaned up code. Added */
  51. /*                       comments.              */
  52. /*    8805       WM      Added code to display  */
  53. /*                       description of sites   */
  54. /*                       for those people who   */
  55. /*                       don't know node names  */
  56. /*                       by heart.              */
  57. /*                                              */
  58. /* Requires: BITNET LINKS file, available from  */
  59. /*           LISTSERV@BITNIC                    */
  60. /************************************************/
  61.  
  62.  
  63. /* General setup.  The user's home node is extracted from IDENTIFY. */
  64. /* Two arguments are expected: a start node and a destination node. */
  65. /* If no start node is given, the default is the user's home node.  */
  66. /* Failure to give any arguments results in a help message.         */
  67.  
  68. 'identify (stack'
  69. parse pull . . localnode .
  70. parse arg from to .
  71. upper from to
  72. if from = ''
  73.    then do
  74.       say 'Syntax : NODE fromnode tonode'
  75.       say '    or : NODE tonode'
  76.       exit 1
  77.    end
  78. if to = ''
  79.    then do
  80.       to = from
  81.       from = localnode
  82.    end
  83.  
  84. /* Finding the routing path between the two nodes.  The file  */
  85. /* BITNET LINKS is read completely onto the stack. After get- */
  86. /* ting past the file header, the information for each node   */
  87. /* is placed in an array indexed by node name.  For instance, */
  88. /* the array element bitnet.UKCC contains the value "UKCCB",  */
  89. /* which is UKCC's connection to the net at large.  This loop */
  90. /* continues as long as there are lines on the stack.         */
  91. /*                                                            */
  92. /* The array description. contains the site description.      */
  93.  
  94. say 'Finding path from 'from' to 'to
  95. say
  96. 'execio * diskr bitnet links * (finis'
  97. beforestart = 1
  98. bitnet. = ''
  99. description. = ''
  100. do queued()
  101.    parse pull 6 node ' ' 15 root ' ' 25 sitename 62 .
  102.    if root = 'ROOT' then beforestart = 0
  103.    if beforestart then iterate
  104.    bitnet.node = root
  105.    description.node = sitename
  106. end
  107.  
  108. /* Finding the path from the start node to the destination node. */
  109. /* The first element of the uplist structure is the start node.  */
  110. /* The home node's connection node, as stored in the array cre-  */
  111. /* ated above, is added to the uplist structure.  The array is   */
  112. /* then scanned for the next connection.  This process continues */
  113. /* until we get to the "ROOT" entry, which means we've gone as */
  114. /* far as we can. Notice that this approach will rarely find the */
  115. /* complete path.  That's fine; we don't want the complete path  */
  116. /* yet.  We want the path back to ROOT, which is CUNYVM. After */
  117. /* we find the path to CUNYVM for the destination node, we will  */
  118. /* simply find the two paths' common ground and go from there.   */
  119.  
  120. uppoint = 0        /* Initialize counter */
  121. uplist.0 = from    /* First element of uplist is start node */
  122. updesc.0 = description.from
  123. do while uplist.uppoint ^= 'ROOT'  /* As long as connections exist */
  124.    lookup = uplist.uppoint           /* Index by node name */
  125.    updesc.uppoint = description.lookup /* Get the site description */
  126.    uppoint = uppoint + 1             /* Increment counter */
  127.    uplist.uppoint = bitnet.lookup /* Next node = connection of last */
  128.    if uplist.uppoint = ''         /* If null, exit */
  129.       then do
  130.          say 'No entry for 'lookup' found'
  131.          exit 999
  132.       end
  133. end
  134.  
  135. /* Find path back from destination node to CUNYVM (root).   */
  136. /* This is accomplished in the same manner as the uplist    */
  137. /* created above.                                           */
  138.  
  139. dnpoint = 0
  140. dnlist.0 = to
  141. dndesc.dnpoint = description.to
  142. do while dnlist.dnpoint ^= 'ROOT'
  143.    lookup = dnlist.dnpoint
  144.    dndesc.dnpoint = description.lookup
  145.    dnpoint = dnpoint + 1
  146.    dnlist.dnpoint = bitnet.lookup
  147.    if dnlist.dnpoint = ''
  148.       then do
  149.         say 'No entry for 'lookup' found'
  150.         exit 999
  151.       end
  152. end
  153.  
  154. /* Find the common ground between the two lists.  Basically,  */
  155. /* we are finding the halfway point, i.e. that point at which */
  156. /* the uplist and downlist merge.  As the uplist is printed,  */
  157. /* the downlist is scanned for a match. Once a match is found */
  158. /* in the downlist, the uplist is dropped, and the downlist   */
  159. /* "takes up where we left off", working back to our goal.    */
  160.  
  161. count = 0                /* Initialize node count */
  162. do loop = 0 to uppoint   /* Do as long as elements remain in uplist */
  163.    prnt = justify(uplist.loop,12)  /* Justify for nice printing */
  164.    say prnt updesc.loop  /* Output the information */
  165.    count = count + 1     /* Increment node count */
  166.    do search = 0 to dnpoint /* Search all elements of dnlist */
  167.       match = 0          /* Set match flag low */
  168.       if uplist.loop = dnlist.search /* If we find a match,        */
  169.          then do
  170.             match = 1                /* set the flag high,         */
  171.             dnpoint = search -1      /* set startpoint for dnlist, */
  172.             leave search             /* and get out of here        */
  173.          end
  174.    end
  175.    if match then leave loop          /* If match flag high, quit   */
  176. end
  177. do loop = dnpoint to 0 by -1     /* Working back from match point, */
  178.    prnt = justify(dnlist.loop,12) /* Justify for nice output */
  179.    say prnt dndesc.loop  /* Output site and description */
  180.    count = count + 1             /* and increment node count       */
  181. end
  182. say
  183. say count - 1' nodes away'       /* Print node count               */
  184. exit count -1                    /* Returned value is node count   */
  185. return                           /* That's all, folks!             */
  186. --------------End REXX code----------------
  187.  
  188. And now, the Unix shell script:
  189.  
  190. --------------Begin Unix shell script-----------------
  191. #!/bin/sh
  192. #
  193. # bitpath - Determine path between two BITNET nodes
  194. #
  195. # Written by Wes Morgan, morgan@engr.uky.edu, 27 Jun 91
  196. #
  197. # This shell script requires the BITNET LINKS file, which is available
  198. # from LISTSERV@BITNIC (aka listserv@bitnic.bitnet).
  199. #
  200. # Syntax: bitpath [-f] [site1] site2
  201. #    If -f is specified, a "full" listing is output, containing each
  202. #        site's description and ISO country code.
  203. #    If "site1" is specified, it will be used as the origin for the
  204. #        search.  If omitted, the site named in DEFAULT, below,
  205. #        will be used as the origin.
  206. #    "site2" is the destination node for the search.
  207. #
  208. # This shell script has been tested under AT&T System V Release 3.2.3  
  209. #
  210. # Known problems:
  211. #    Some entries contain descriptions which "run into" the ISO
  212. #    country code.  If this happens, you will see an extra field
  213. #    (the "software" field) displayed for that site.
  214.  
  215. # LINKFILE should be set to the name of your copy of BITNET LINKS.
  216. LINKFILE=bitlinks
  217.  
  218. # DEFAULT should be set to the default origin node for searches.
  219. # This nodename MUST be in CAPTIAL LETTERS!! 
  220. # I use UKCC, which is the University of Kentucky Computing Center.
  221. DEFAULT=UKCC
  222.  
  223. #
  224. # Parse the command line.
  225. #
  226. errflag=0
  227. full=0
  228. if [ -z "$1" ]
  229. then
  230.     errflag=1
  231. fi
  232. if [ "$1" = "-f" -o "$1" = "-F" ]
  233. then
  234.     full=1
  235.     shift
  236. fi
  237. if [ -z "$1" ]
  238. then
  239.     errflag=1
  240. else
  241.     if [ -z "$2" ]
  242.     then
  243.         upnode=$DEFAULT
  244.         uplist=$DEFAULT
  245.         dnnode=`echo $1 | tr "[a-z]" "[A-Z]"`
  246.         dnlist=$dnnode
  247.     else
  248.         upnode=`echo $1 | tr "[a-z]" "[A-Z]"`
  249.         uplist=$upnode
  250.         dnnode=`echo $2 | tr "[a-z]" "[A-Z]"`
  251.         dnlist=$dnnode
  252.     fi
  253. fi
  254.  
  255. if [ $errflag -eq 1 ]
  256. then
  257.     echo Syntax: bitpath [-f] [site1] site2
  258.     exit 1
  259. fi
  260. echo
  261.  
  262. #
  263. # BITNET is a tree-based network, originating from the City University
  264. # of New York (CUNYVM).  Therefore, our initial task is to determine the
  265. # path from the origin node back to the "root" at CUNYVM.  
  266. #
  267. # The format of BITNET LINKS is as follows:
  268. # 0693 UKCC     UGA       U Kentucky Comp Ctr              ,US RSCS  91/03/31
  269. # From right to left, the fields are:
  270. #    - BITNET node number (unused in this script)
  271. #    - Site name
  272. #    - The next site up the network tree
  273. #    - Description of the site
  274. #    - ISO country code
  275. #    - Network software used for BITNET  (unused in this script)
  276. #    - Last update of this site's entry (unused in this script)
  277. #
  278. # At this stage, we are only interested in the second and third fields.
  279. # We will construct a list of sites from the origin to CUNYVM.  Since
  280. # CUNYVM is the root of the BITNET tree, it's "next site" entry is "ROOT";
  281. # we use that entry to end the search loop.
  282.  
  283. updone=0
  284. while [ $updone -eq 0 ]
  285. do
  286.     line=`grep $upnode $LINKFILE | awk '$2 ~ /^'"$upnode"'$/'`
  287.     if [ -z "$line" ]
  288.     then
  289.         echo "No entry for $upnode found."
  290.         exit 1
  291.     fi
  292.     next=`echo $line | awk '{ print $3 }'`
  293.     if [ "$next" = "ROOT" ] 
  294.     then
  295.         updone=1
  296.     else
  297.         upnode=$next
  298.         uplist=`echo $uplist $next`
  299.     fi
  300. done
  301.  
  302. #
  303. # Construct a path from the destination node to CUNYVM (the root).
  304. # The algorithm is identical; the only change is that we construct
  305. # the list in reverse order.
  306. #
  307.  
  308. dndone=0
  309. while [ $dndone -eq 0 ]
  310. do
  311.     line=`grep $dnnode $LINKFILE | awk '$2 ~ /^'"$dnnode"'$/'`
  312.     if [ -z "$line" ]
  313.     then
  314.         echo "No entry for $dnnode found."
  315.         exit 1
  316.     fi
  317.     next=`echo $line | awk '{ print $3 }'`
  318.     if [ "$next" = "ROOT" ] 
  319.     then
  320.         dndone=1
  321.     else
  322.         dnnode=$next
  323.         dnlist=`echo $next $dnlist`
  324.     fi
  325. done
  326.  
  327. #
  328. # Now that we have our two paths, we need to find the "common ground"
  329. # between them.  We move through the list from left to right.  At each
  330. # step, we scan ahead, looking for a duplicate entry.  If we find one,
  331. # that site is the "common ground"; we skip over to the duplicate and
  332. # finish the path from that point.  
  333. #
  334. # For instance, the path from UKCC (Kentucky) through CUNYVM (the root) to
  335. # SUVM (Syracuse) is generated as:
  336. #    UKCC UGA CUNYVMV2 CUNYVM CUNYVM CUNYVMV2 CORNELLC SUVM
  337. # We don't need the redundant "CUNVMV2 CUNYVM CUNYVM CUNYVMV2" portion of
  338. # this path, because actual network traffic will not reach CUNYVM; it will
  339. # be routed from CUMYVMV2 to CORNELLC.  Therefore, in this example, CUNYVMV2
  340. # is the "common ground" for which this section of code searches.
  341. #
  342.  
  343. cleanlist=`echo "$uplist $dnlist" | awk '    { for(x=1;x<=NF;x++) {
  344.                     print $x;
  345.                     for(y=x+1;y<=NF;y++) {
  346.                         if($y == $x) {
  347.                             x = y;
  348.                             break;
  349.                         }
  350.                     }
  351.                           }
  352.                     }'`
  353.  
  354. #
  355. # Output results.  If the -f option is used, the listing includes
  356. # site description and country code; if not, only the node names
  357. # are printed, separated with "->".
  358. #
  359. if [ $full -eq 1 ]
  360. then
  361.     echo $cleanlist | 
  362.     awk '{ for(x=1;x<=NF;x++) printf("%s\n",$x); }' |
  363.     while read target
  364.     do
  365.         line=`grep $target $LINKFILE | awk '$2 ~ /^'"$target"'$/'`
  366.         descrip=`echo $line | awk '{ for(x=4;x<NF;x++) {
  367.                         printf("%s ",$x); 
  368.                         if (index($x,",") == 1) x=NF;
  369.                         }
  370.                        }
  371.                        END { printf("\n"); }'`
  372.         justify=`echo $target | awk '{ printf("%-8s",$1); }'`
  373.         echo "$justify\t$descrip"
  374.     done
  375.     echo
  376. else 
  377.     echo $cleanlist | sed "s/ /->/g"
  378. fi
  379. exit 0
  380. ------------------end Unix shell script----------------------
  381.  
  382. -- 
  383.  morgan@ms.uky.edu    |Wes Morgan, not speaking for|     ....!ukma!ukecc!morgan
  384.  morgan@engr.uky.edu  |the University of Kentucky's|   morgan%engr.uky.edu@UKCC
  385.  morgan@ie.pa.uky.edu |Engineering Computing Center| morgan@wuarchive.wustl.edu
  386.