home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / dump_cls.zip / dump_cls.cmd
OS/2 REXX Batch file  |  1999-06-24  |  14KB  |  401 lines

  1. /* 
  2. program:   dump_cls.cmd
  3. type:      Object REXX, REXXSAA 6.0, all platforms
  4. purpose:   collection of useful routines for Object REXX programs
  5. version:   1.00.00
  6. date:      1999-06-24
  7. changed:   -
  8.  
  9. author:    Rony G. Flatscher
  10.            Rony.Flatscher@wu-wien.ac.at
  11.            (Wirtschaftsuniversitaet Wien, University of Economics and Business
  12.            Administration, Vienna/Austria/Europe)
  13.  
  14. needs:     "rgf_util.cmd" from the "orx8.zip"-package (cf. ::REQUIRES-directive below)
  15.  
  16. usage (1): dump_cls
  17.            ... displays the present Object Rexx class hierarchy.
  18.  
  19. usage (2): dump_cls FILE_TO_CALL [ARGS]
  20.            ... calls the given file with optional arguments and
  21.                reports the classes and the methods defined by it.
  22.  
  23. comments:  -
  24.  
  25. Standard disclaimer (sometimes larger than the entire program! :) :
  26.  
  27. All rights reserved and copyrighted 1999 by the author, no guarantee that
  28. it works without errors, etc.  etc.
  29.  
  30. You are granted the right to use this module under the condition that you don't
  31. charge money for this module (as you didn't write it in the first place) or
  32. modules directly derived from this module, that you document the original author
  33. (to give appropriate credit) with the original name of the module and that you
  34. make the unaltered, original source-code of this module available on demand.  If
  35. that holds, you may even bundle this module (either in source or compiled form)
  36. with commercial software.
  37.  
  38. If you find an error, please send me the description (preferably a *very* short
  39. example); I'll try to fix it and re-release it to the net.
  40. */
  41.  
  42. PARSE ARG file args             /* retrieve file to analyze */
  43.  
  44.                 /* configuration        */
  45. .local ~ n.bSAM = .false        /* show all methods ? If .false, then only for new classes      */
  46. /*
  47. .local ~ n.bSAM = .true
  48. */
  49.  
  50.  
  51. .local ~ n.nda = "(n/a)"        /* save "not in .local or .environment"         */
  52. .local ~ n.new = ">>"           /* new-class indicator                          */
  53. .local ~ n.new.string = COPIES(" ", LENGTH(.n.new))
  54. .local ~ n.mc  = "(MC)"         /* indicator for metaclass class                */
  55.  
  56. .local ~ n.pointer = "->"       /* string to indicate pointer                   */
  57.  
  58. .local ~ n.length = 80          /* line-length for breaking up lines            */
  59. .local ~ n.Indent = 5           /* blanks to indent, if line was broken up      */
  60. .local ~ n.ind.bl = COPIES(" ", .n.indent)      /* blank-indentation string     */
  61.  
  62.  
  63.                 /* start of program     */
  64. tmpSet1 = getSetOfClasses(.object)      /* get a set of all classes             */
  65.  
  66. IF file="" THEN                 /* no arguments, give usage-message     */
  67. DO
  68.    PARSE SOURCE . . thisFile
  69.    SAY 
  70.    SAY "Usage (1):" FILESPEC("N", thisFile) 
  71.    SAY "           ... displays the present Object Rexx class hierarchy."
  72.    SAY
  73.    SAY "Usage (2):" FILESPEC("N", thisFile) "FILE_TO_CALL [ARGS]"
  74.    SAY "           ... calls the given file with optional arguments and"
  75.    SAY "               reports the classes and the methods defined by it."
  76.    SAY
  77.    SAY
  78.    SAY "Object Rexx class tree as of:" "[" || date("s") time() || "]"
  79.    SAY
  80.            /* ---> show class-hierarchy    */
  81.    CALL dump_sub_classes .object, 0, .set~new
  82.    SAY
  83.    SAY .n.nda "= not available through .local or .environment!"
  84.    SAY .n.mc "= metaclass used for the listed class"
  85.    SAY "There are" pp(tmpSet1~items) "distinct classes in the tree."
  86.    SAY
  87.    EXIT 0
  88. END
  89.  
  90.         /* create Rexx call instruction, execute it, possibly new classes now available           */
  91. tmpDat = "CALL (file)" args
  92. INTERPRET tmpDat
  93. tmpSet2 = getSetOfClasses(.object)      /* get a set of all classes             */
  94.  
  95. tmpSetNew = tmpSet2~difference(tmpSet1) /* extract new classes                  */
  96.  
  97. .local~n.SetPre = tmpSet1               /* classes before calling file          */
  98. .local~n.SetNew = tmpSetNew             /* classes defined because of file      */
  99. .local~n.SetAll = tmpSet2               /* all classes                          */
  100.  
  101. tmpRel = .relation~new
  102. IF .n.bSAM THEN tmpSet = .n.SetAll      /* show all methods or only those of new classes */
  103.            ELSE tmpSet = .n.SetNew
  104. DO class OVER tmpSet
  105.    class_Id = class~id
  106.    MethSupp = class~methods(.nil)       /* get methods defined in class         */
  107.    DO WHILE MethSupp~available          /* loop over all methods                */
  108.       tmpRel[MethSupp~index]=class_id
  109.       MethSupp~next
  110.    END 
  111. END
  112.  
  113. .local~n.M2C = tmpRel                   /* .n.c2m[method-name]=class_id         */
  114.  
  115.  
  116.  
  117. IF tmpSetNew~items=0 THEN               /* no new classes defined               */
  118. DO
  119.    SAY "File" pp( file ) "did not define new classes, aborting."
  120.    EXIT -1
  121. END
  122.  
  123. SAY "Analyzing classes and methods introduced by:" pp( file ) "[" || date("s") time() || "]"
  124. SAY
  125.  
  126.         /* ---> show class-hierarchy    */
  127. CALL dump_sub_classes .object, 0, tmpSetNew
  128. SAY
  129. SAY .n.nda "= not in .local or .environment!"
  130. SAY pp(.n.SetNew~items) "new classes - prefixed with" pp(.n.new) "- were introduced by" pp(file) 
  131. SAY
  132.  
  133. SAY COPIES("=", .n.length)
  134.  
  135.  
  136.         /* ---> show classes in alpha together with their methods in alpha 
  137.                (show superclasses, if they have the same method-name    */
  138. SAY
  139. SAY pp( file )": Classes and their methods (showing superclasses with the same method):"
  140. SAY
  141.  
  142. tmpArr = sortCollection(.n.SetAll, "ID")        /* sort set by "ID" of the class objects */
  143. DO i = 1 TO .n.SetAll~items
  144.    CALL class2methods i, tmpArr[i, 1], tmpArr[i, 2]     /* show class and its messages   */ 
  145. END
  146. SAY
  147. SAY COPIES("=", .n.length)
  148.  
  149.  
  150.  
  151.         /* ---> show methods in alpha together with the classes in alpha */
  152. SAY
  153. SAY pp( file )": Methods and Classes, which define them:"
  154.  
  155. tmpSupp = .n.m2c~supplier
  156. tmpArr  = .array~new
  157. null    = "01"x
  158. i=1
  159. DO WHILE tmpSupp~available
  160.    tmpArr[i]=tmpSupp~index || null || tmpSupp~item      /* index=methodname, item=class_id      */
  161.    i=i+1
  162.    tmpSupp~next
  163. END
  164. SAY "(total of" pp(tmpArr~items) "methods)"
  165. SAY
  166.  
  167. tmpArr = sortArray(tmpArr)                              /* sort array                           */
  168. tmpString = ""
  169. bNew   = .true
  170. MsgWidth = 30
  171. .local ~ n.ind.bl = COPIES(" ", MsgWidth+1)             /* to be used by break_and_say as a lead-in     */
  172. PARSE VALUE tmpArr[1] WITH OldMethod (null)
  173. DO i = 1 TO tmpArr~items
  174.    PARSE VALUE tmpArr[i] WITH newMethod (null) class_id
  175.    bNew = (OldMethod \== newMethod)
  176.    IF bNew THEN
  177.    DO
  178.       call break_and_say LEFT(pp(oldMethod)" ", MAX(MsgWidth, LENGTH(oldMethod)), '.') STRIP( STRIP(tmpString, "T", "," ))
  179.       tmpString = ""
  180.       OldMethod = newMethod
  181.    END
  182.    tmpString = tmpString class_id","
  183. END
  184. IF tmpString <> "" THEN
  185.    call break_and_say LEFT(pp(oldMethod)" ", MAX(MsgWidth, LENGTH(oldMethod)), '.') STRIP( STRIP(tmpString, "T", "," ))
  186.  
  187. SAY
  188. SAY COPIES("=", .n.length)
  189.  
  190.  
  191.  
  192. ::REQUIRES "rgf_util.cmd"       /* loads all bunch of utility-routines, using pp() and sorting-routines */
  193.  
  194.  
  195.         /* show class and a list of its methods; if method by the same name exists
  196.            in superclass, then show it in order of resolution (takes care of multiple
  197.            inheritance) */
  198. ::ROUTINE class2methods
  199.   USE ARG idx, class_id, class
  200.  
  201.   tmpSC = class~superclasses    /* get superclasses     */
  202.   tmpMC = class~metaclass       /* get metaclass        */
  203.   tmpMArr = sortArray(.n.m2c~allindex(class_id))   /* get all methods of class_id  */
  204.  
  205.   CALL say_class                /* build and show class infos   */
  206. /*
  207.   CALL say_methods tmpMArr      /* simple message-listing       */
  208. */
  209.   CALL say_methods_with_super tmpMArr, class
  210.   RETURN
  211.  
  212.   say_class :                   /* build and show class infos   */
  213.      tmpString = LEFT(class_id, MAX(20, LENGTH(class_id)), ".")
  214.      IF .n.SetNew~hasindex(class) THEN tmpString = .n.new        || tmpString
  215.                                   ELSE tmpString = .n.new.string || tmpString
  216.  
  217.      IF tmpSC~items <> 0 THEN
  218.      DO
  219.         IF class~querymixinclass THEN tmpString = tmpString "MIXINCLASS" tmpSC[1]~id
  220.                                  ELSE tmpString = tmpString "SUBCLASS  " tmpSC[1]~id 
  221.      END
  222.  
  223.      IF tmpMC <> .class THEN tmpString = tmpString "METACLASS" tmpMC~id
  224.      IF tmpSC~items > 1 THEN    /* multiple inheritance?        */
  225.      DO
  226.         tmpString = tmpString "INHERIT"         /* build inherit list   */
  227.         DO i=2 TO tmpSC~items
  228.            tmpString = tmpString tmpSC~at(i)~id
  229.         END
  230.      END
  231.      IF tmpMArr~items <> 0 THEN SAY     /* insert empty line before class, if it has methods */
  232.      SAY tmpString
  233.      RETURN
  234.  
  235.   say_methods_with_super : PROCEDURE    /* show methods and superclasses, if they have that method too */
  236.      USE ARG methArr, class
  237.  
  238.      CResList = createSuper(class)      /* create class-resolution list */
  239.      tmpString=""
  240.      DO item OVER methArr
  241.         tmpString = tmpString pp(item) 
  242.         bSkip = 1; /* bNotFirst = 0 */
  243.         do citem over CResList
  244.            if bSkip then                /* first element in list is class itself, skip it */
  245.            do 
  246.               bSkip=0;iterate
  247.            end 
  248.            tmpCID = citem~id
  249.            if .n.m2c~hasitem(tmpCID,item) then
  250.            do
  251.               tmpString = tmpString || .n.pointer || tmpCID
  252.            end
  253.         end 
  254.         tmpString = tmpString","
  255.      END
  256.      IF tmpString <> "" THEN 
  257.      DO
  258.         call break_and_say .n.ind.bl || STRIP( STRIP(tmpString, "T", "," ))
  259.         SAY
  260.      END
  261.      return
  262.  
  263.   createSuper: procedure                /* create list of superclass-resolution, take care of multiple inheritance */
  264.      use arg class
  265.  
  266.      CResList = .list ~ new             /* class resolution list        */
  267.      last = CResList ~ last             /* get last entry, everything has to be inserted right after it */
  268.      CALL get_hierarchy_up Class, .set~new, CResList, last
  269.  
  270. /*
  271. say "first:" CResList~firstitem~id "last:" CResList~lastitem~id 
  272. tmpString =""
  273. do item over CResList
  274.    tmpString = tmpString "-->"item~id
  275. end 
  276. say tmpString
  277. */
  278.      return CResList
  279.  
  280. /* ---------------------------------------------------------------------------------------- */
  281. /* produce a hierarchy list with starting class, taking care of multiple inheritance    */
  282. /* insert aClass into CResList, if it is not in tmpSet,
  283.    position in list is indicated by POSITION_IN_LIST */
  284.  
  285. GET_HIERARCHY_UP: PROCEDURE 
  286.    USE ARG aClass, tmpSet, CResList, position_in_list
  287.  
  288.    IF tmpSet ~ hasindex( aClass ) THEN RETURN   /* already handled */
  289.                                                 /* insert class after given entry       */
  290.    listIndex = CResList ~insert(aClass, position_in_list)
  291.    tmpSet ~ put( aClass )                       /* indicate that class has been handled */
  292.  
  293.    arrSC = aClass ~ SuperClasses                /* get all superclasses of aClass       */
  294.    DO i=arrSC~items TO 1 BY -1                  /* work from right to left              */
  295.       item = arrSC ~ at(i)                      /* retrieve superclass                  */
  296.       IF \tmpSet ~ HASINDEX(item) THEN          /* class not handled as of yet          */
  297.       DO
  298.          CALL get_hierarchy_up item, tmpSet, CResList, listIndex
  299.       END
  300.    END
  301.    RETURN
  302.  
  303.  
  304.  
  305.  
  306.   say_methods : PROCEDURE       /* show plain methods   */
  307.      USE ARG methArr
  308.  
  309.      tmpString=""
  310.      DO item OVER methArr
  311.         tmpString = tmpString pp(item) 
  312.      END
  313.      IF tmpString <> "" THEN 
  314.      DO
  315.        call break_and_say .n.ind.bl || STRIP( tmpString )
  316.        SAY
  317.      END
  318.      return
  319.  
  320.  
  321.  
  322. ::ROUTINE break_and_say
  323.   USE ARG line, 
  324.  
  325.   compLength = .n.length+1
  326.   DO WHILE line <> ""
  327.      IF LENGTH(line) < compLength THEN
  328.      DO
  329.         SAY line
  330.         LEAVE
  331.      END
  332.  
  333.      ELSE
  334.      DO
  335.         pos = LASTPOS(" ", line, compLength)
  336.                 /* no blanks in string so far=oversized line? (exclude leadin blanks!)  */
  337.         IF pos<=.n.indent THEN pos = POS(" ", line, compLength)
  338.         IF pos=0 THEN pos=length(line)+1        /* no blank in oversized line   */
  339.  
  340.         SAY SUBSTR(line, 1, pos-1)              /* extract string up to but not including blank   */
  341.         line=.n.ind.bl || SUBSTR(line, pos+1)
  342.      END
  343.   END
  344.      
  345.      
  346.  
  347.  
  348. ::ROUTINE dump_sub_classes
  349.   USE ARG class, level, tmpSetNew
  350.  
  351.   class_id = class~id
  352.   tmpString = class_id
  353.                                 /* not directly available thru .local or .environment?  */
  354.   IF (.local~entry(class_id) = .nil) & (.environment~entry(class_id) = .nil) THEN tmpString = tmpString .n.nda
  355.  
  356.                                 /* newly added class?                   */
  357.   IF tmpSetNew~hasindex(class) THEN tmpString = .n.new        || tmpString 
  358.                                ELSE tmpString = .n.new.string || tmpString  /* insert blank (s) */
  359.  
  360.   IF class~SuperClasses~items > 1 THEN  /* class employing multiple inheritance?        */
  361.   DO
  362.      superclasses = class~SuperClasses
  363.      tmpString2 = "[subclass" SuperClasses[1]~id "inherit"
  364.      DO i=2 TO superclasses~items       /* create list of multiple inherited classes    */
  365.         tmpString2 = tmpString2 superclasses~at(i)~id
  366.      END
  367.      tmpString = tmpString tmpString2 || "]"
  368.   END
  369.  
  370. /*
  371.   SAY LEFT(LEFT("", level * 4) || tmpString, MAX( 58, LENGTH(tmpString)+level*4), ".") class~metaclass~string 
  372. */
  373.   SAY LEFT(LEFT("", level * 4) || tmpString, MAX( 63, LENGTH(tmpString)+level*4), ".") .n.mc  class~metaclass~id
  374.  
  375.   subclasses = sortArray(class~SUBCLASSES)      /* sort array of subclasses of class in hand */
  376.  
  377.   DO subclass OVER subclasses
  378.      CALL dump_sub_classes subclass, level + 1, tmpSetNew
  379.   END
  380.   RETURN
  381.  
  382.  
  383.  
  384.   /* create a Set which contains the passed in class and all of its subclasses  */
  385. ::ROUTINE getSetOfClasses
  386.   USE ARG class
  387.   tmpSet = .set~new
  388.   CALL gsoc class, tmpSet
  389.   RETURN tmpSet
  390.  
  391.   gsoc: PROCEDURE               /* does the work, recursively   */
  392.      use arg class,tmpSet
  393.      tmpSet~put(class)
  394.      subclasses = class~subclasses
  395.      DO sclass OVER subclasses
  396.         call gsoc sclass, tmpSet
  397.      END
  398.      RETURN
  399.  
  400.  
  401.